logo
IntroductionHow to add CSS or JavaScript files to an Android/iOS projectHow to combat autoplay policiesPlayback issue with Internet Explorer 11Why does fullscreen not behave as expected on iOSWhy does the network API not work on iOS devicesWhy doesn't Chromecast work when embedded in an iframe on iOSWhy can't I select another video quality on iOSIs YouTube supportedWhy does the player load only one audio track (even though there are several in the manifest)Is it possible to see 360 degrees photo with THEOplayerWhy the visibility API does not work through an iframe on Safari and IE11What is an impressionHow to do error handlingHow to know whether a live stream is playingWhich error related events does the player exposeWhy did my subtitles stop workingHow does Media Engagement Index (MEI) affect Autoplay on ChromeWhat does the error message 'Unknown CDM error' meanWhat does the error message 'Something went wrong with Native playback' meanWhy are not all response headers exposedWhy does the currentTime seem off in my livestream & what can I do about itHow to remove CORS restrictions from a reproduction streamWhich network calls (or requests) does THEOplayer doWhy does the playback not work when using the Chrome iPhone/iPad simulatorWhat does the error message 'can only be initiated by a user gesture' imply? Can I still force the desired actionHow to remove unwanted CC track in iOS or SafariKnown Chromecast Limitations in 2.61.1What are the Product Flavor options in the Android SDK (minApi16 and minApi21)Why do I get a grey play button in my Android WebView and how to remove it?I'm unable to inspect Webview with the Android SDKMediaTek limitationsHow to fix Android DRM in Chrome 74How to use ProGuard with THEOplayer Android SDKSelf-hosting and versioning of THEOplayerDoes THEOplayer support EXT-X-DATERANGECan clipping be used on a playlistCan timeline thumbnails be made available before playback startWhat are the benefits of preloadingWhat are are the player seeking and seeked events and when are they firedCan we use HLS adsHow to change text in THEOplayerChange text when AirplayingITP2.1 problems using THEOplayerRemoving context menu/'Powered by THEOplayer v2...'What aspects of THEOplayer do we need to take into account to deploy a proper Content Security Policy (CSP)How can we avoid that the player keeps looking for chunks/segments if they are not foundCan we show a custom message on 403 on mp4Can we prevent UpNext feature from redirectingIs it possible to preload VOD content while the pre-roll is playingWhy is my video not playing automaticallyIs it possible to have multiple player instances play at the same timeIs it a problem if the viewer pauses a live stream for longer than the DVR windowTHEOplayer Features/ModulesChromecast on my webplayer does not work any longer despite no change in my implementationHow to track network errorsWhat is the support for WowzaHow to use the CDN fallback/backup stream featureHow to apply accurate buffering strategyHow can I distribute 4K content?What is the collaboration between Azure Media Services and THEOplayer

Why does the currentTime seem off in my livestream & what can I do about it

THEOplayer has a currentTime property, which returns you the current playback position in the video (in seconds). For VOD this works as you would expect. If you have a video, let it play for 30 seconds and query the currentTime, the player will report 30 seconds. However, if you start watching a livestream and query the currentTime after 30 seconds, you won't get 30 seconds reported. Nor will you get the time that would have elapsed if you watched the segments in the most recent manifest file until the point where you queried the currentTime. This might seem odd, but there's a very good reason for this, which we'll explain in a bit, along with some workarounds if you do want to use one of the aforementioned definitions of currentTime in a live streaming context.

To calculate the currentTime, THEOplayer follows the HTML5 specification. However, for livestreams, this is not specified. Hence, if you try to use currentTime for synchronisation between players, you'd get different behaviour among different players. It's even possible to see different behaviour among different streaming protocols in conjunction with the same player.

The internal implementation THEOplayer uses, is constructed to never have a negative currentTime. A few things are being checked to ensure this:

  • Check if it's a VOD. In this case the timeline starts at 0
  • In case it's a live stream, there are two options

It's a live-EVENT stream

  • Manifest contains EXT-X-PLAYLIST-TYPE: EVENT
  • All renditions started at the same time, so the first segment would have timestamp 0

It's a livestream with a DVR window

  • For these some players choose to start the 0-offset at the start of the first segment
  • However, segments are not necessarily aligned across multiple renditions:
  • Switching renditions can cause new content to become available before the start timestamps of the first rendition
  • Such a segments would halve a negative start timestamp
  • To avoid negative timestamps, THEOplayer keeps an offset of 3 target durations from the start as its zero-reference

How can you deal with this if you want to synchronise players or get a zero-based timestamp? You have 3 options:

  1. Use EXT-X-PROGRAM-DATE-TIME, which gives you an absolute time reference.
  2. Make your stream an event stream by including EXT-X-PLAYLIST-TYPE: EVENT in the manifest
  3. Use the player's seekable property (which is based on the manifest) and query seekable.start(0) to find the starting time of your stream 3.1 Attach an event listener for the 'durationchange' event (triggered the first time a media playlist is loaded) 3.2 Upon this event, store player.seekable.start(0) in a variable 'timeOffset' and remove the eventlistener 3.3 Subtract the value of 'timeOffset' from the player's currentTime to get a zero-based timestamp

Here's a code snippet for option 3 :

function AbsoluteTimeline(player) {
    var timeOffset = 0;

    function durationchangeHandler () {
        timeOffset = player.seekable.start(0);
        player.removeEventListener('durationchange', durationchangeHandler);
    }
    player.addEventListener('durationchange', durationchangeHandler);

    return {
        getOffset: function() {
            return timeOffset;
        },
        getCurrentTime: function() {
            return player.currentTime - timeOffset;
        },
        seek: function(timestamp) {
            player.currentTime = timestamp + timeOffset;
        }
    }
}

var timeline = AbsoluteTimeline(player);
github
Make sure to follow us on GitHub!
THEO-logo-white
twitter
facebook
linkedin
Copyright © 2020. All Rights Reserved.
Leuven
New York
San Francisco
Singapore
Barcelona