jwplayer / jwplayer

JW Player is the world's most popular embeddable media player.
https://developer.jwplayer.com/
Other
2.53k stars 976 forks source link

[Question] How implement a video feed with autoplay #3033

Closed renzit closed 5 years ago

renzit commented 6 years ago

Expected Behavior

I want to have a video feed with videos embedded with programmatic setup through js. I expect that the videos had autoplay when is in the viewport and autopause when isnt visible.

Actual Behavior

Well i made some test: 1) The first video with autostart on true, the others with autostart on viewable. (It doesnt had pause when the video isnt visible) 2) I made my own implementation on scroll event to play and pause

  $(window).scroll(function () {
    Object.keys(jwVideos).forEach(function (id) {
      if (jwVideos[id].instance.getViewable()) {
        if (!jwVideos[id].user_interaction) {
          jwVideos[id].instance.play();
        }
      } else {
        // The video loses the user interaction when it's not viewable
        jwVideos[id].user_interaction = false;
        jwVideos[id].instance.pause();
      }
    });
  });

But this code brings unexpected behaviors.

1) Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause() https://developers.google.com/web/updates/2017/06/play-request-was-interrupted And cant do the google recommendation with the play of jw because it return an object not a promise.

2) Problems on mobile devices. a)On iphone when you scroll to the latest videos (20 videos in the feed) the latest had problems on the player showing an error, (errorId: 233000) **When the users open only that video in another page it doesnt have the problems described.

b) On android the player doesnt have errors but sometimes all the videos only shows the last frame that load and nothing more, even when you play and pause with clicks.

Steps to reproduce

  1. Go to https://www.vix.com/en/yum

Problem 1) Scroll into the video feed, watch the console and the Uncaught (in promise) will appear if using chrome 50+ Problem 2) . On iphone (if in chrome disallow save data or interact to use the autoplay/pause) and scroll to the latest videos and it would show error 233000

I would like to hear if somebody else already did a video feed with autoplay, or what are the recommendation to do this.

thank you in advance :)

robwalch commented 6 years ago

Hi @renzit,

You should avoid using scroll event handlers as they can impact page performance. The player emits a "viewable" event when it goes in and out of view when scrolling. The event also includes fullscreen (viewable=1) and the tab being hidden (viewable=0).

On mobile you can't initiate playback with sound programatically. So you'll need to mute your video on mobile.

jwplayer('your-player-id').setup({
    file: 'your-video-file',
    mute: jwplayer().getEnvironment().OS.mobile,
    events: {
        viewable: function(e) {
            if (e.viewable) {
                this.play();
            } else {
                this.pause();
            }
        }
    }
});

You also can just use autostart, where you get this behavior for free on mobile:

jwplayer('your-player-id').setup({
    file: 'your-video-file',
    autostart: true
});

Try a combination of autostart and viewable event handling to get the behavior you want. You should also look at the playReason and pauseReason properties of these events to determine what caused a play or pause. "interaction" means the user clicked play or pause. "external" means that it was a call to the api like this.play().

    events: {
        playAttempt: function(e) {
            console.warn(e);
        },
        play: function(e) {
            console.warn(e);
        },
        pause: function(e) {
            console.warn(e);
        }
    }
renzit commented 6 years ago

First thanks for the answer @robwalch , that suggestion really improve our code, using the scroll event wasnt a good idea he.

And I want to share a little modification:

events: {
    viewable: function(e) {
      var state = jwplayer(jwVideoID).getState();
      if (e.viewable) {
        this.play();
      } else {
        if (state != 'buffering') {
          this.pause();
        }
      }
    }

AND

jwplayer(jwVideoID).on("play", function (e) {
    var is_viwable = jwplayer(jwVideoID).getViewable()
    if(!is_viwable){
        jwplayer(jwVideoID).pause();
    }
});

In this case I added a validation because if the video is in the state 'Buffering', then doesn't matter if it is viewable because the call to play and pause generates the uncaught exception. What was happening: 1) VideoJW was visible and it sends the play action 2) VideoJW isn't visible anymore but the state was buffering and sent the pause (this generate uncaught exception).

With this in production so far is a win.

But we still have some problems. 1) if the user Interact and pauses the video that is buffering then shows the uncaught exception.

2) The problem in the iphones continues. (i think lazy loading like 5 videos each time could have a benefit) but i want to know if you have another approach or know why is that problem.

3) Now Im hooked in the on play event to check if a buffered video starts playing and if its not visible i pause it. I prefer a event when the buffering is ready or any suggestion if this could be improved.

Iphone technical issues with jw video:

techical-problem-videojw-on-iphone.MP4.zip

robwalch commented 5 years ago

@renzit This is now supported in setup options:

{
    autostart: 'viewable',
    autoPause: {
        viewability: true
    }
}