@@ -1715,7 +1715,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
17151715 }
17161716
17171717 // Schedule buffer control
1718- private checkBuffer ( ) {
1718+ private checkBuffer ( starved ?: boolean ) {
17191719 const items = this . schedule . items ;
17201720 if ( ! items ) {
17211721 return ;
@@ -1726,8 +1726,11 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
17261726 this . timelinePos ,
17271727 0 ,
17281728 ) ;
1729-
1730- this . updateBufferedPos ( bufferInfo . end , items , bufferInfo . len === 0 ) ;
1729+ if ( starved ) {
1730+ this . bufferedPos = this . timelinePos ;
1731+ }
1732+ starved ||= bufferInfo . len < 1 ;
1733+ this . updateBufferedPos ( bufferInfo . end , items , starved ) ;
17311734 }
17321735
17331736 private updateBufferedPos (
@@ -1788,10 +1791,13 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
17881791 } else if (
17891792 bufferIsEmpty &&
17901793 playingItem &&
1791- ! this . itemsMatch ( playingItem , bufferingItem ) &&
1792- bufferEndIndex === playingIndex
1794+ ! this . itemsMatch ( playingItem , bufferingItem )
17931795 ) {
1794- this . bufferedToItem ( playingItem ) ;
1796+ if ( bufferEndIndex === playingIndex ) {
1797+ this . bufferedToItem ( playingItem ) ;
1798+ } else if ( bufferEndIndex === playingIndex + 1 ) {
1799+ this . bufferedToItem ( items [ bufferEndIndex ] ) ;
1800+ }
17951801 }
17961802 }
17971803
@@ -1930,7 +1936,13 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
19301936 if ( neverLoaded ) {
19311937 const timelineStart = interstitial . timelineStart ;
19321938 if ( interstitial . appendInPlace ) {
1933- this . flushFrontBuffer ( timelineStart + 0.25 ) ;
1939+ const playingItem = this . playingItem ;
1940+ if (
1941+ ! this . isInterstitial ( playingItem ) &&
1942+ playingItem ?. nextEvent ?. identifier === interstitial . identifier
1943+ ) {
1944+ this . flushFrontBuffer ( timelineStart + 0.25 ) ;
1945+ }
19341946 }
19351947 let hlsStartOffset ;
19361948 let liveStartPosition = 0 ;
@@ -1998,6 +2010,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
19982010 if ( ! requiredTracks ) {
19992011 return ;
20002012 }
2013+ this . log ( `Removing front buffer starting at ${ startOffset } ` ) ;
20012014 const sourceBufferNames = Object . keys ( requiredTracks ) ;
20022015 sourceBufferNames . forEach ( ( type : SourceBufferName ) => {
20032016 this . hls . trigger ( Events . BUFFER_FLUSHING , {
@@ -2087,12 +2100,13 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
20872100 }
20882101 }
20892102 }
2103+ const assetId = assetItem . identifier ;
20902104 const playerConfig : Partial < HlsConfig > = {
20912105 ...userConfig ,
20922106 autoStartLoad : true ,
20932107 startFragPrefetch : true ,
20942108 primarySessionId : primary . sessionId ,
2095- assetPlayerId : assetItem . identifier ,
2109+ assetPlayerId : assetId ,
20962110 abrEwmaDefaultEstimate : primary . bandwidthEstimate ,
20972111 interstitialsController : undefined ,
20982112 startPosition,
@@ -2114,6 +2128,11 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
21142128 contentId : hash ( assetItem . uri ) ,
21152129 } ) ;
21162130 }
2131+ if ( this . getAssetPlayer ( assetId ) ) {
2132+ this . warn (
2133+ `Duplicate date range identifier ${ interstitial } and asset ${ assetId } ` ,
2134+ ) ;
2135+ }
21172136 const player = new HlsAssetPlayer (
21182137 this . HlsPlayerClass ,
21192138 playerConfig ,
@@ -2122,7 +2141,6 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
21222141 ) ;
21232142 this . playerQueue . push ( player ) ;
21242143 interstitial . assetList [ assetListIndex ] = assetItem ;
2125- const assetId = assetItem . identifier ;
21262144 // Listen for LevelDetails and PTS change to update duration
21272145 const updateAssetPlayerDetails = ( details : LevelDetails ) => {
21282146 if ( details . live ) {
@@ -2181,14 +2199,12 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
21812199 }
21822200 } ;
21832201 player . on ( Events . BUFFER_CODECS , onBufferCodecs ) ;
2184- const bufferedToEnd = ( name : Events . BUFFERED_TO_END ) => {
2202+ const bufferedToEnd = ( ) => {
21852203 const inQueuPlayer = this . getAssetPlayer ( assetId ) ;
21862204 this . log ( `buffered to end of asset ${ inQueuPlayer } ` ) ;
21872205 if ( ! inQueuPlayer ) {
21882206 return ;
21892207 }
2190- inQueuPlayer . off ( Events . BUFFERED_TO_END , bufferedToEnd ) ;
2191-
21922208 // Preload at end of asset
21932209 const scheduleIndex = this . schedule . findEventIndex (
21942210 interstitial . identifier ,
@@ -2202,7 +2218,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
22022218 ! interstitial . isAssetPastPlayoutLimit ( nextAssetIndex ) &&
22032219 ! interstitial . assetList [ nextAssetIndex ] . error
22042220 ) {
2205- this . bufferedToItem ( item , assetListIndex + 1 ) ;
2221+ this . bufferedToItem ( item , nextAssetIndex ) ;
22062222 } else {
22072223 const nextItem = this . schedule . items ?. [ scheduleIndex + 1 ] ;
22082224 if ( nextItem ) {
@@ -2228,6 +2244,30 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
22282244 player . once ( Events . MEDIA_ENDED , endedWithAssetIndex ( assetListIndex ) ) ;
22292245 player . once ( Events . PLAYOUT_LIMIT_REACHED , endedWithAssetIndex ( Infinity ) ) ;
22302246 player . on ( Events . ERROR , ( event : Events . ERROR , data : ErrorData ) => {
2247+ const inQueuPlayer = this . getAssetPlayer ( assetId ) ;
2248+ if ( data . details === ErrorDetails . BUFFER_STALLED_ERROR ) {
2249+ if ( inQueuPlayer ?. media ) {
2250+ const assetCurrentTime = inQueuPlayer . currentTime ;
2251+ const distanceFromEnd = inQueuPlayer . duration - assetCurrentTime ;
2252+ if (
2253+ assetCurrentTime &&
2254+ interstitial . appendInPlace &&
2255+ distanceFromEnd / inQueuPlayer . media . playbackRate < 0.5
2256+ ) {
2257+ this . log (
2258+ `Advancing buffer past end of asset ${ assetId } ${ interstitial } at ${ inQueuPlayer . media . currentTime } ` ,
2259+ ) ;
2260+ bufferedToEnd ( ) ;
2261+ } else {
2262+ this . warn (
2263+ `Stalled at ${ assetCurrentTime } of ${ assetCurrentTime + distanceFromEnd } in asset ${ assetId } ${ interstitial } ` ,
2264+ ) ;
2265+ this . onTimeupdate ( ) ;
2266+ this . checkBuffer ( true ) ;
2267+ }
2268+ }
2269+ return ;
2270+ }
22312271 this . handleAssetItemError (
22322272 data ,
22332273 interstitial ,
@@ -2336,10 +2376,8 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
23362376 } ) ;
23372377 }
23382378
2339- if ( ! player . bufferedInPlaceToEnd ( media ) ) {
2340- // detach media and attach to interstitial player if it does not have another element attached
2341- this . bufferAssetPlayer ( player , media ) ;
2342- }
2379+ // detach media and attach to interstitial player if it does not have another element attached
2380+ this . bufferAssetPlayer ( player , media ) ;
23432381 }
23442382
23452383 private bufferAssetPlayer ( player : HlsAssetPlayer , media : HTMLMediaElement ) {
@@ -2569,6 +2607,12 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
25692607 if ( interstitial ) {
25702608 this . primaryFallback ( interstitial ) ;
25712609 }
2610+ break ;
2611+ }
2612+ case ErrorDetails . BUFFER_STALLED_ERROR : {
2613+ this . onTimeupdate ( ) ;
2614+ this . checkBuffer ( true ) ;
2615+ break ;
25722616 }
25732617 }
25742618 }
0 commit comments