The Trouble with Seeking

If you use ad rules, you may run into a problem with click-and-drag seeking. Specifically, after a user clicks and drags to seek through video past multiple midroll pods, they may see 2 or more of those pods play back to back before content resumes. This is caused by the video playhead time updating while the user is seeking; if the SDK happens to poll for the current time while the user seeks past an ad, it may think that ad should be played. When the content resumes, it will play that ad, and then the most recent ad since the seek. For a visual representation of this problem, see the diagram below:

The simple way to solve this is save the current time when the user starts seeking, and report that time when the SDK asks for it until the user resumes normal playback. For a visual representation of this solution, see the diagram below:

With this solution, we properly skip the 0:10 mid-roll and only play the 0:20 mid-roll. This is done using a custom playhead tracker, as shown below. The code below contains modifications (shown in bold) of ads.js in the advanced HTML5 sample available on our download page.

var Ads = function(application, videoPlayer) {
  ...
  this.currentTime = 0;
  setInterval(this.updateCurrentTime, 1000);
};

Ads.prototype.updateCurrentTime = function() {
  if (!this.videoPlayer_.contentPlayer.seeking) {
    this.currentTime = this.videoPlayer_.contentPlayer.currentTime;
  }
};

Ads.prototype.onAdsManagerLoaded_ = function(adsManagerLoadedEvent) {
  this.application_.log('Ads loaded.');
  this.adsManager_ = adsManagerLoadedEvent.getAdsManager(this);
  this.processAdsManager_(this.adsManager_);
};

Known issues with Mobile Safari

This method should work on every plaform except mobile Safari. On mobile Safari, the seeking property of the video tag is not properly implemented (it will always return false). To get around that, we need to do our own check to see if the user is seeking through the video. The sample code for this method follows. Again, the bolded lines below are modifications to existing code.

var Ads = function(application, videoPlayer) {
  ...
  this.currentTime = 0;
  setInterval(this.updateCurrentTime, 1000);
  this.seeking = false;
  this.seekCheckInterval = 1000;
  // You may need to adjust this value, depending on your platform
  this.seekThreshold = 100;
  this.previousTime = 0;
  setInterval(
      Application.bind(this, this.checkForSeeking),
      this.seekCheckInterval);
};

Ads.prototype.updateCurrentTime = function() {
  if (!this.seeking) {
    this.currentTime = this.videoPlayer_.contentPlayer.currentTime;
  }
};

Ads.prototype.checkForSeeking = function() {
  var currentTime = this.videoPlayer_.contentPlayer.currentTime;
  // How much time has passed since we last ran this method, in milliseconds
  var diff = (currentTime - this.previousTime) * 1000;
  // If that difference is greater than the time since we last ran this method,
  // plus our threshold, the user was seeking
  if (Math.abs(diff)  > this.interval + this.threshold) {
    this.seeking = true;
  } else {
    this.seeking = false;
  }
  // Grab the current video time again to make up for time spent in this method
  previousTime = this.videoPlayer_.contentPlayer.currentTime;
};

Ads.prototype.onAdsManagerLoaded_ = function(adsManagerLoadedEvent) {
  this.application_.log('Ads loaded.');
  this.adsManager_ = adsManagerLoadedEvent.getAdsManager(this);
  this.processAdsManager_(this.adsManager_);
};

With these changes, the SDK is now using the currentTime property of your Ads object to determine when to play ad breaks, not the currentTime property of the content video player.

Send feedback about...

IMA SDK for HTML5
Need help? Visit our support page.