snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
/* eslint-disable no-invalid-this */
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import YouTube from 'react-youtube';
|
||||
|
||||
import { PLAYBACK_STATUSES } from '../../constants';
|
||||
|
||||
import AbstractVideoManager, {
|
||||
IProps,
|
||||
_mapDispatchToProps,
|
||||
_mapStateToProps
|
||||
} from './AbstractVideoManager';
|
||||
|
||||
/**
|
||||
* Manager of shared video.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
class YoutubeVideoManager extends AbstractVideoManager {
|
||||
isPlayerAPILoaded: boolean;
|
||||
player?: any;
|
||||
|
||||
/**
|
||||
* Initializes a new YoutubeVideoManager instance.
|
||||
*
|
||||
* @param {Object} props - This component's props.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.isPlayerAPILoaded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the playback state of the video.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
override getPlaybackStatus() {
|
||||
let status;
|
||||
|
||||
if (!this.player) {
|
||||
return;
|
||||
}
|
||||
|
||||
const playerState = this.player.getPlayerState();
|
||||
|
||||
if (playerState === YouTube.PlayerState.PLAYING) {
|
||||
status = PLAYBACK_STATUSES.PLAYING;
|
||||
}
|
||||
|
||||
if (playerState === YouTube.PlayerState.PAUSED) {
|
||||
status = PLAYBACK_STATUSES.PAUSED;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the video is muted.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
override isMuted() {
|
||||
return this.player?.isMuted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves current volume.
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
override getVolume() {
|
||||
return this.player?.getVolume();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves current time.
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
override getTime() {
|
||||
return this.player?.getCurrentTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks video to provided time.
|
||||
*
|
||||
* @param {number} time - The time to seek to.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
override seek(time: number) {
|
||||
// allowSeekAhead, so a seek outside the buffered range is honoured
|
||||
// instead of being deferred. A follower is the first caller to reach this
|
||||
// on a player that has not started (opened while the meeting's video is
|
||||
// paused), where the default would leave it on the thumbnail rather than
|
||||
// at the shared position.
|
||||
return this.player?.seekTo(time, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays video.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
override play() {
|
||||
return this.player?.playVideo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses video.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
override pause() {
|
||||
return this.player?.pauseVideo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes video.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
override mute() {
|
||||
return this.player?.mute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmutes video.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
override unMute() {
|
||||
return this.player?.unMute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes of the current video player.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
override dispose() {
|
||||
if (this.player) {
|
||||
this.player.destroy();
|
||||
this.player = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired on play state toggle.
|
||||
*
|
||||
* @param {Object} event - The yt player stateChange event.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
onPlayerStateChange = (event: any) => {
|
||||
if (event.data === YouTube.PlayerState.PLAYING) {
|
||||
this.onPlay();
|
||||
} else if (event.data === YouTube.PlayerState.PAUSED) {
|
||||
this.onPause();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fired when youtube player is ready.
|
||||
*
|
||||
* @param {Object} event - The youtube player event.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
onPlayerReady = (event: any) => {
|
||||
const { _isOwner, follower } = this.props;
|
||||
|
||||
this.player = event.target;
|
||||
|
||||
this.player.addEventListener('onVolumeChange', () => {
|
||||
this.onVolumeChange();
|
||||
});
|
||||
|
||||
if (_isOwner) {
|
||||
this.player.addEventListener('onVideoProgress', this.throttledFireUpdateSharedVideoEvent);
|
||||
}
|
||||
|
||||
if (follower) {
|
||||
// The player only exists now, so this is where a follower first
|
||||
// gets to reconcile with the meeting's shared state; it also stays
|
||||
// muted, since a follower plays no audio.
|
||||
this.syncFollower();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.play();
|
||||
|
||||
// sometimes youtube can get muted state from previous videos played in the browser
|
||||
// and as we are disabling controls we want to unmute it
|
||||
if (this.isMuted()) {
|
||||
this.unMute();
|
||||
}
|
||||
};
|
||||
|
||||
getPlayerOptions = () => {
|
||||
const { _isOwner, follower, videoId } = this.props;
|
||||
const showControls = _isOwner ? 1 : 0;
|
||||
|
||||
const options = {
|
||||
id: 'sharedVideoPlayer',
|
||||
opts: {
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
playerVars: {
|
||||
'origin': location.origin,
|
||||
'fs': '0',
|
||||
'autoplay': 0,
|
||||
'controls': showControls,
|
||||
'rel': 0,
|
||||
|
||||
// A follower plays no audio; starting it muted also keeps
|
||||
// the browser from blocking its (scripted) playback.
|
||||
...follower ? { 'mute': 1 } : {}
|
||||
}
|
||||
},
|
||||
onError: (e: any) => this.onError(e),
|
||||
onReady: this.onPlayerReady,
|
||||
onStateChange: this.onPlayerStateChange,
|
||||
videoId
|
||||
};
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements React Component's render.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
override render() {
|
||||
return (
|
||||
<YouTube
|
||||
{ ...this.getPlayerOptions() } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps, _mapDispatchToProps)(YoutubeVideoManager);
|
||||
Reference in New Issue
Block a user