Reputation: 1116
I am building a multimedia player that needs to control multiple other multimedia players on a page. In order to do that I want to have an area at the bottom of the page which contains a media playback controller (including a seekbar) that will control all other players on the page. For example, when a user hits the play button all the other players on the page starts playing.
I want to use a regular video/audio player, but instead of playing real content all I want is to have the controls, especially a seekbar which advances. The reason for not implementing playback controls on my own is because I want to use the power of video.js plugins (like event markers on the timeline).
I have managed to display a video.js player only with playback controls. In addition I have managed to set the duration. The problem is that the player doesn't play when I hit the play button nor calilng player.play()
.
This is because the player doesn't have a media source. video.js and the native player won't play without a media source.
Now, is there a way to force a player to play even without a source? Can I make it think it has one?
Thank you,
Upvotes: 2
Views: 1189
Reputation: 1116
I have figured out a solution that works.
Again the purpose is having working media controllers from video.js without loading any media content and the most important controller is the seek bar.
I have been playing with video.js and was trying to make the seek bar advance without loading any media content and found out that calling player.currentTime()
does actually updates the curretTime
internal member but doesn't update the UI.
Eventually I found out that in order to make video.js update the UI we need to trigger the timeupdate
event.
So I decided to implement a fake player that has control over all the other players and uses a video.js player as his UI (by showing only the media controls and hiding the video).
The fake player need to use a precise timer as mentioned here.
Conceptual example:
import videojs from 'video.js';
class MainMediaController {
public static readonly INTERVAL = 250;
protected _playerId: string;
protected _duration: number;
protected _mediaController: videojs.Player;
protected _childPlayers: videojs.Player[];
protected _currentTime: number;
private _interval: number;
private _intervalId: number;
constructor(playerId: string, recordingDuration: number, childPlayers: videojs.Player[]) {
this._playerId = playerId; // id of the player at the bottom of the page which will be served as the main timeline
this._duration = recordingDuration;
this._interval = MainMediaController.INTERVAL;
this._childPlayers = childPlayers;
this._currentTime = 0;
}
public async init() {
this._mediaController = videojs(this._playerId);
// await for ready state
await new Promise((resolve, reject) => {
this._mediaController.ready(() => {
resolve();
});
});
// set duration for a correct seek bar (longest.endTime - first.startTime)
this._mediaController.duration(this._duration);
}
public play(){
// update UI every 250ms
this._intervalId = setInterval(this.intervalStep.bind(this), this._interval);
for(let player of this._childPlayers){
player.play();
}
}
private intervalStep(){
this._currentTime += 0.250; // 250ms
this._mediaController.currentTime(this._currentTime);
this._mediaController.trigger("timeupdate"); // trigger() is accessible don't worry
}
public pause(){...}
public stop(){...}
public seek(){...}
}
That solution let me use video.js plugins in my main timeline that has no video in it!!
Upvotes: 2
Reputation: 580
It's the same principle for images. If you don't have an image for some content, you need to have a backup plan : a placeholder image.
You can do the same with videos.
The simplest solution is to have in your project directory :
> placeholders
|-- fakeVideo_short.mp4
|-- fakeVideo-long.mp4
|-- fakeAudio.mp3
|-- ...
Whenever your upper media controller finds an empty player, you can just feed it a placeholder content.
It's an easy solution that allows you to focus more quickly on wants important : The media controller.
Well :
Upvotes: 1