@@ -27,7 +27,7 @@ export const syncPointStrategies = [
2727 {
2828 name : 'ProgramDateTime' ,
2929 run : ( syncController , playlist , duration , currentTimeline , currentTime ) => {
30- if ( ! syncController . datetimeToDisplayTime ) {
30+ if ( ! Object . keys ( syncController . timelineToDatetimeMappings ) . length ) {
3131 return null ;
3232 }
3333
@@ -39,10 +39,16 @@ export const syncPointStrategies = [
3939
4040 for ( let i = 0 ; i < segments . length ; i ++ ) {
4141 const segment = segments [ i ] ;
42+ const datetimeMapping =
43+ syncController . timelineToDatetimeMappings [ segment . timeline ] ;
44+
45+ if ( ! datetimeMapping ) {
46+ continue ;
47+ }
4248
4349 if ( segment . dateTimeObject ) {
4450 const segmentTime = segment . dateTimeObject . getTime ( ) / 1000 ;
45- const segmentStart = segmentTime + syncController . datetimeToDisplayTime ;
51+ const segmentStart = segmentTime + datetimeMapping ;
4652 const distance = Math . abs ( currentTime - segmentStart ) ;
4753
4854 // Once the distance begins to increase, or if distance is 0, we have passed
@@ -161,7 +167,7 @@ export default class SyncController extends videojs.EventTarget {
161167 // ...for synching across variants
162168 this . timelines = [ ] ;
163169 this . discontinuities = [ ] ;
164- this . datetimeToDisplayTime = null ;
170+ this . timelineToDatetimeMappings = { } ;
165171
166172 this . logger_ = logger ( 'SyncController' ) ;
167173 }
@@ -351,19 +357,25 @@ export default class SyncController extends videojs.EventTarget {
351357 }
352358
353359 /**
354- * Save the mapping from playlist's ProgramDateTime to display. This should
355- * only ever happen once at the start of playback .
360+ * Save the mapping from playlist's ProgramDateTime to display. This should only happen
361+ * before segments start to load .
356362 *
357363 * @param {Playlist } playlist - The currently active playlist
358364 */
359- setDateTimeMapping ( playlist ) {
360- if ( ! this . datetimeToDisplayTime &&
361- playlist . segments &&
365+ setDateTimeMappingForStart ( playlist ) {
366+ // It's possible for the playlist to be updated before playback starts, meaning time
367+ // zero is not yet set. If, during these playlist refreshes, a discontinuity is
368+ // crossed, then the old time zero mapping (for the prior timeline) would be retained
369+ // unless the mappings are cleared.
370+ this . timelineToDatetimeMappings = { } ;
371+
372+ if ( playlist . segments &&
362373 playlist . segments . length &&
363374 playlist . segments [ 0 ] . dateTimeObject ) {
364- const playlistTimestamp = playlist . segments [ 0 ] . dateTimeObject . getTime ( ) / 1000 ;
375+ const firstSegment = playlist . segments [ 0 ] ;
376+ const playlistTimestamp = firstSegment . dateTimeObject . getTime ( ) / 1000 ;
365377
366- this . datetimeToDisplayTime = - playlistTimestamp ;
378+ this . timelineToDatetimeMappings [ firstSegment . timeline ] = - playlistTimestamp ;
367379 }
368380 }
369381
@@ -377,14 +389,15 @@ export default class SyncController extends videojs.EventTarget {
377389 * The current active request information
378390 * @param {boolean } options.shouldSaveTimelineMapping
379391 * If there's a timeline change, determines if the timeline mapping should be
380- * saved in timelines .
392+ * saved for timeline mapping and program date time mappings .
381393 */
382394 saveSegmentTimingInfo ( { segmentInfo, shouldSaveTimelineMapping } ) {
383395 const didCalculateSegmentTimeMapping = this . calculateSegmentTimeMapping_ (
384396 segmentInfo ,
385397 segmentInfo . timingInfo ,
386398 shouldSaveTimelineMapping
387399 ) ;
400+ const segment = segmentInfo . segment ;
388401
389402 if ( didCalculateSegmentTimeMapping ) {
390403 this . saveDiscontinuitySyncInfo_ ( segmentInfo ) ;
@@ -394,10 +407,16 @@ export default class SyncController extends videojs.EventTarget {
394407 if ( ! segmentInfo . playlist . syncInfo ) {
395408 segmentInfo . playlist . syncInfo = {
396409 mediaSequence : segmentInfo . playlist . mediaSequence + segmentInfo . mediaIndex ,
397- time : segmentInfo . segment . start
410+ time : segment . start
398411 } ;
399412 }
400413 }
414+
415+ const dateTime = segment . dateTimeObject ;
416+
417+ if ( segment . discontinuity && shouldSaveTimelineMapping && dateTime ) {
418+ this . timelineToDatetimeMappings [ segment . timeline ] = - ( dateTime . getTime ( ) / 1000 ) ;
419+ }
401420 }
402421
403422 timestampOffsetForTimeline ( timeline ) {
@@ -433,7 +452,7 @@ export default class SyncController extends videojs.EventTarget {
433452 const segment = segmentInfo . segment ;
434453 let mappingObj = this . timelines [ segmentInfo . timeline ] ;
435454
436- if ( segmentInfo . timestampOffset !== null ) {
455+ if ( typeof segmentInfo . timestampOffset === 'number' ) {
437456 mappingObj = {
438457 time : segmentInfo . startOfSegment ,
439458 mapping : segmentInfo . startOfSegment - timingInfo . start
0 commit comments