Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
6e8af81d
authored
Jan 07, 2021
by
bachinger
Committed by
Ian Baker
Jan 08, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Reload HLS media playlist when merging delta update fails
Issue: #5011 PiperOrigin-RevId: 350550204
parent
6dec8323
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
46 additions
and
16 deletions
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTrackerTest.java
testdata/src/test/assets/media/m3u8/live_low_latency_media_can_skip_until_and_block_reload_next_skipped
testdata/src/test/assets/media/m3u8/live_low_latency_media_can_skip_until_full_reload_after_error
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java
View file @
6e8af81d
...
@@ -603,11 +603,16 @@ public final class DefaultHlsPlaylistTracker
...
@@ -603,11 +603,16 @@ public final class DefaultHlsPlaylistTracker
loadDurationMs
,
loadDurationMs
,
loadable
.
bytesLoaded
());
loadable
.
bytesLoaded
());
boolean
isBlockingRequest
=
loadable
.
getUri
().
getQueryParameter
(
BLOCK_MSN_PARAM
)
!=
null
;
boolean
isBlockingRequest
=
loadable
.
getUri
().
getQueryParameter
(
BLOCK_MSN_PARAM
)
!=
null
;
if
(
isBlockingRequest
&&
error
instanceof
HttpDataSource
.
InvalidResponseCodeException
)
{
boolean
deltaUpdateFailed
=
error
instanceof
HlsPlaylistParser
.
DeltaUpdateException
;
int
responseCode
=
((
HttpDataSource
.
InvalidResponseCodeException
)
error
).
responseCode
;
if
(
isBlockingRequest
||
deltaUpdateFailed
)
{
if
(
responseCode
==
400
||
responseCode
==
503
)
{
int
responseCode
=
Integer
.
MAX_VALUE
;
// Intercept bad request and service unavailable to force a full, non-blocking request
if
(
error
instanceof
HttpDataSource
.
InvalidResponseCodeException
)
{
// (see RFC 8216, section 6.2.5.2).
responseCode
=
((
HttpDataSource
.
InvalidResponseCodeException
)
error
).
responseCode
;
}
if
(
deltaUpdateFailed
||
responseCode
==
400
||
responseCode
==
503
)
{
// Intercept failed delta updates and blocking requests producing a Bad Request (400) and
// Service Unavailable (503). In such cases, force a full, non-blocking request (see RFC
// 8216, section 6.2.5.2 and 6.3.7).
earliestNextLoadTimeMs
=
SystemClock
.
elapsedRealtime
();
earliestNextLoadTimeMs
=
SystemClock
.
elapsedRealtime
();
loadPlaylist
();
loadPlaylist
();
castNonNull
(
eventDispatcher
)
castNonNull
(
eventDispatcher
)
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
View file @
6e8af81d
...
@@ -69,6 +69,9 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
...
@@ -69,6 +69,9 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
*/
*/
public
final
class
HlsPlaylistParser
implements
ParsingLoadable
.
Parser
<
HlsPlaylist
>
{
public
final
class
HlsPlaylistParser
implements
ParsingLoadable
.
Parser
<
HlsPlaylist
>
{
/** Exception thrown when merging a delta update fails. */
public
static
final
class
DeltaUpdateException
extends
IOException
{}
private
static
final
String
LOG_TAG
=
"HlsPlaylistParser"
;
private
static
final
String
LOG_TAG
=
"HlsPlaylistParser"
;
private
static
final
String
PLAYLIST_HEADER
=
"#EXTM3U"
;
private
static
final
String
PLAYLIST_HEADER
=
"#EXTM3U"
;
...
@@ -744,8 +747,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -744,8 +747,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
checkState
(
previousMediaPlaylist
!=
null
&&
segments
.
isEmpty
());
checkState
(
previousMediaPlaylist
!=
null
&&
segments
.
isEmpty
());
int
startIndex
=
(
int
)
(
mediaSequence
-
castNonNull
(
previousMediaPlaylist
).
mediaSequence
);
int
startIndex
=
(
int
)
(
mediaSequence
-
castNonNull
(
previousMediaPlaylist
).
mediaSequence
);
int
endIndex
=
startIndex
+
skippedSegmentCount
;
int
endIndex
=
startIndex
+
skippedSegmentCount
;
if
(
startIndex
>=
0
&&
endIndex
<=
previousMediaPlaylist
.
segments
.
size
())
{
if
(
startIndex
<
0
||
endIndex
>
previousMediaPlaylist
.
segments
.
size
())
{
// Merge only if all skipped segments are available in the previous playlist.
// Throw to force a reload if not all segments are available in the previous playlist.
throw
new
DeltaUpdateException
();
}
for
(
int
i
=
startIndex
;
i
<
endIndex
;
i
++)
{
for
(
int
i
=
startIndex
;
i
<
endIndex
;
i
++)
{
Segment
segment
=
previousMediaPlaylist
.
segments
.
get
(
i
);
Segment
segment
=
previousMediaPlaylist
.
segments
.
get
(
i
);
if
(
mediaSequence
!=
previousMediaPlaylist
.
mediaSequence
)
{
if
(
mediaSequence
!=
previousMediaPlaylist
.
mediaSequence
)
{
...
@@ -774,7 +779,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -774,7 +779,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
}
}
segmentMediaSequence
++;
segmentMediaSequence
++;
}
}
}
}
else
if
(
line
.
startsWith
(
TAG_KEY
))
{
}
else
if
(
line
.
startsWith
(
TAG_KEY
))
{
String
method
=
parseStringAttr
(
line
,
REGEX_METHOD
,
variableDefinitions
);
String
method
=
parseStringAttr
(
line
,
REGEX_METHOD
,
variableDefinitions
);
String
keyFormat
=
String
keyFormat
=
...
...
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTrackerTest.java
View file @
6e8af81d
...
@@ -37,7 +37,6 @@ import okhttp3.mockwebserver.MockWebServer;
...
@@ -37,7 +37,6 @@ import okhttp3.mockwebserver.MockWebServer;
import
okio.Buffer
;
import
okio.Buffer
;
import
org.junit.After
;
import
org.junit.After
;
import
org.junit.Before
;
import
org.junit.Before
;
import
org.junit.Ignore
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
...
@@ -50,6 +49,8 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -50,6 +49,8 @@ public class DefaultHlsPlaylistTrackerTest {
"media/m3u8/live_low_latency_master_media_uri_with_param"
;
"media/m3u8/live_low_latency_master_media_uri_with_param"
;
private
static
final
String
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL
=
private
static
final
String
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL
=
"media/m3u8/live_low_latency_media_can_skip_until"
;
"media/m3u8/live_low_latency_media_can_skip_until"
;
private
static
final
String
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL_FULL_RELOAD_AFTER_ERROR
=
"media/m3u8/live_low_latency_media_can_skip_until_full_reload_after_error"
;
private
static
final
String
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_DATERANGES
=
private
static
final
String
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_DATERANGES
=
"media/m3u8/live_low_latency_media_can_skip_dateranges"
;
"media/m3u8/live_low_latency_media_can_skip_dateranges"
;
private
static
final
String
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_SKIPPED
=
private
static
final
String
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_SKIPPED
=
...
@@ -168,18 +169,21 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -168,18 +169,21 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
mergedPlaylist
.
segments
.
get
(
1
).
relativeStartTimeUs
).
isEqualTo
(
4000000
);
assertThat
(
mergedPlaylist
.
segments
.
get
(
1
).
relativeStartTimeUs
).
isEqualTo
(
4000000
);
}
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
@Test
public
void
start_playlistCanSkip_missingSegments_
correctedMediaSequence
()
public
void
start_playlistCanSkip_missingSegments_
reloadsWithoutSkipping
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
throws
IOException
,
TimeoutException
,
InterruptedException
{
List
<
HttpUrl
>
httpUrls
=
List
<
HttpUrl
>
httpUrls
=
enqueueWebServerResponses
(
enqueueWebServerResponses
(
new
String
[]
{
new
String
[]
{
"/master.m3u8"
,
"/media0/playlist.m3u8"
,
"/media0/playlist.m3u8?_HLS_skip=YES"
"/master.m3u8"
,
"/media0/playlist.m3u8"
,
"/media0/playlist.m3u8?_HLS_skip=YES"
,
"/media0/playlist.m3u8"
},
},
getMockResponse
(
SAMPLE_M3U8_LIVE_MASTER
),
getMockResponse
(
SAMPLE_M3U8_LIVE_MASTER
),
getMockResponse
(
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL
),
getMockResponse
(
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL
),
getMockResponse
(
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_SKIPPED_MEDIA_SEQUENCE_NO_OVERLAPPING
));
getMockResponse
(
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_SKIPPED_MEDIA_SEQUENCE_NO_OVERLAPPING
),
getMockResponse
(
SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL_FULL_RELOAD_AFTER_ERROR
));
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
...
@@ -192,8 +196,8 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -192,8 +196,8 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
initialPlaylistWithAllSegments
.
mediaSequence
).
isEqualTo
(
10
);
assertThat
(
initialPlaylistWithAllSegments
.
mediaSequence
).
isEqualTo
(
10
);
assertThat
(
initialPlaylistWithAllSegments
.
segments
).
hasSize
(
6
);
assertThat
(
initialPlaylistWithAllSegments
.
segments
).
hasSize
(
6
);
HlsMediaPlaylist
mergedPlaylist
=
mediaPlaylists
.
get
(
1
);
HlsMediaPlaylist
mergedPlaylist
=
mediaPlaylists
.
get
(
1
);
assertThat
(
mergedPlaylist
.
mediaSequence
).
isEqualTo
(
2
2
);
assertThat
(
mergedPlaylist
.
mediaSequence
).
isEqualTo
(
2
0
);
assertThat
(
mergedPlaylist
.
segments
).
hasSize
(
4
);
assertThat
(
mergedPlaylist
.
segments
).
hasSize
(
6
);
}
}
@Test
@Test
...
...
testdata/src/test/assets/media/m3u8/live_low_latency_media_can_skip_until_and_block_reload_next_skipped
View file @
6e8af81d
...
@@ -2,8 +2,8 @@
...
@@ -2,8 +2,8 @@
#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24,CAN-BLOCK-RELOAD=YES
#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24,CAN-BLOCK-RELOAD=YES
#EXT-X-TARGETDURATION:4
#EXT-X-TARGETDURATION:4
#EXT-X-VERSION:3
#EXT-X-VERSION:3
#EXT-X-SKIP:SKIPPED-SEGMENTS=2
#EXT-X-MEDIA-SEQUENCE:12
#EXT-X-MEDIA-SEQUENCE:12
#EXT-X-SKIP:SKIPPED-SEGMENTS=2
#EXTINF:4.00000,
#EXTINF:4.00000,
fileSequence14.ts
fileSequence14.ts
#EXTINF:4.00000,
#EXTINF:4.00000,
...
...
testdata/src/test/assets/media/m3u8/live_low_latency_media_can_skip_until_full_reload_after_error
0 → 100644
View file @
6e8af81d
#EXTM3U
#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24
#EXT-X-TARGETDURATION:4
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:20
#EXTINF:4.00000,
fileSequence20.ts
#EXTINF:4.00000,
fileSequence21.ts
#EXTINF:4.00000,
fileSequence22.ts
#EXTINF:4.00000,
fileSequence23.ts
#EXTINF:4.00000,
fileSequence24.ts
#EXTINF:4.00000,
fileSequence25.ts
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment