In a game we are building we are using html videos.
On desktop the game is working as expected. However, on tablet devices the first video is playing and later in the game when the next video is called it won’t play.
These videos are shown like this:
VideoManager.prototype.playVideo = function (videoName) {
if (VideoManager.isPlaying === true) {
return;
}
VideoManager.isPlaying = true;
// Create HTML Video Element to play the video
var video = document.createElement('video');
VideoManager.video = video;
video.id = 'video';
video.loop = false;
// muted attribute is required for videos to autoplay
video.muted = false;
if (this.app.touch) {
video.controls = true;
}
// critical for iOS or the video won't initially play, and will go fullscreen when playing
video.playsInline = true;
// needed because the video is being hosted on a different server url
video.crossOrigin = "anonymous";
// autoplay the video
video.autoplay = false;
// set video source
var videoFile = this.app.assets.find(videoName).getFileUrl();
video.src = videoFile;
// iOS video texture playback requires that you add the video to the DOMParser
// with at least 1x1 as the video's dimensions
var videoStyle = video.style;
videoStyle.width = '100vw';
videoStyle.height = '100vh';
videoStyle.position = 'fixed';
videoStyle.opacity = '100%';
videoStyle.zIndex = '1000';
// videoStyle.pointerEvents = 'none';
videoStyle.objectFit = 'cover';
videoStyle.transition = 'all 1s';
videoStyle.opacity = '0';
document.body.appendChild(video);
// video.addEventListener('canplaythrough', function (e) {
video.addEventListener('canplay', function (e) {
// alert("video is ready to play");
this.isPlaying = true;
document.body.appendChild(video);
videoStyle.opacity = '1';
VideoManager.isPlaying = true;
document.body.querySelector('#application-canvas').style.display = "none";
setTimeout(function () {
video.play();
}, 1000);
}.bind(this));
video.addEventListener('ended', function (e) {
document.body.querySelector('#application-canvas').style.display = "block";
this.isPlaying = false;
// alert("video is geeindigd");
videoStyle.opacity = '0';
document.body.removeChild(video);
this.app.fire("video:ended");
VideoManager.isPlaying = false;
}.bind(this));
};
To show the problem without you having to play the game I made a basic scene where I am calling to play a short video 3 times. I am calling them like this.
// initialize code called once per entity
VideoButton.prototype.initialize = function () {
this.entity.element.on("click", function () {
alert("clicked");
setTimeout(function () {
this.app.fire("video:play", "Cutscene.mp4");
}.bind(this), 0);
setTimeout(function () {
this.app.fire("video:play", "Cutscene.mp4");
}.bind(this), 4000);
setTimeout(function () {
this.app.fire("video:play", "Cutscene.mp4");
}.bind(this), 8000);
}, this);
};
What’s surprising me is that the behaviour is different again.
In this example the video won’t show until the user interacts another time.
Does anybody know why this is happening on tablets?
Can you share the test project you are using publicly please?
As the videos are set to play on setTimeout, they may not play properly as iOS and mobile devices are quite specific on video playback to require user input if they aren’t muted
Looks like the issue is due to iOS not firing events on the video element such as canplaythrough or canplay unless there is a user input event AFTER The video element is added to the page or that autoplay and muted are true.
Depending on your needs, you would either need autoplay and muted to be enabled OR add the video element to the document first before trying to play it via the button
Your fork works. However it is muted and I need it to be unmuted.
I managed to fix it by going another route.
In the game I am making the first video did work, also on tablet. The videos after that one did not. So I thought it might be because there are multiple video elements created and deleted and I guess the mobile browsers don’t like that.
So now I am making one video element on launch, hide it and replace the video source when calling the function.
This is my updated code. Note that autoplay = true and muted = false.
var VideoManager = pc.createScript('videoManager');
// initialize code called once per entity
VideoManager.prototype.initialize = function () {
// listen for the video:play event
this.app.on('video:play', this.playVideo, this);
this.app.on('video:skip', function () {
// VideoManager.video.pause();
VideoManager.video.currentTime = VideoManager.video.duration - 1;
}, this);
// remove player:move event listeners when script destroyed
this.on('destroy', function () {
this.app.off('video:play', this.playVideo, this);
});
// Create HTML Video Element to play the video
var video = document.createElement('video');
video.id = 'video';
video.loop = false;
// muted attribute is required for videos to autoplay
video.muted = false;
// critical for iOS or the video won't initially play, and will go fullscreen when playing
video.playsInline = true;
// needed because the video is being hosted on a different server url
video.crossOrigin = "anonymous";
// autoplay the video
video.autoplay = true;
// iOS video texture playback requires that you add the video to the DOMParser
// with at least 1x1 as the video's dimensions
var videoStyle = video.style;
videoStyle.width = '100vw';
videoStyle.height = '100vh';
videoStyle.position = 'fixed';
videoStyle.opacity = '100%';
videoStyle.zIndex = '1000';
videoStyle.objectFit = 'cover';
videoStyle.transition = 'all 1s';
videoStyle.display = 'none';
document.body.appendChild(video);
VideoManager.video = video;
// Keyboard event to test certain scenes
this.app.keyboard.on(pc.EVENT_KEYDOWN, this.onKeyDown, this);
};
// Event handler called when key is pressed
VideoManager.prototype.onKeyDown = function (event) {
// Check event.key to detect which key has been pressed
if (event.key === pc.KEY_SPACE) {
console.log("Space key pressed");
this.app.fire("video:skip");
}
};
VideoManager.prototype.playVideo = function (videoName) {
if (VideoManager.isPlaying === true) {
return;
}
VideoManager.isPlaying = true;
// set video source
var videoFile = this.app.assets.find(videoName).getFileUrl();
VideoManager.video.src = videoFile;
VideoManager.video.style.display = 'block';
document.body.querySelector('#application-canvas').style.display = "none";
video.addEventListener('ended', function (e) {
document.body.querySelector('#application-canvas').style.display = "block";
// alert("video is geeindigd");
VideoManager.video.style.display = 'none';
this.app.fire("video:ended");
VideoManager.isPlaying = false;
}.bind(this));
};