import React from 'react'; import { defineMessages, injectIntl, intlShape } from 'react-intl'; import PropTypes from 'prop-types'; import _ from 'lodash'; import FullscreenService from '../fullscreen-button/service'; import FullscreenButtonContainer from '../fullscreen-button/container'; import { styles } from './styles'; import AutoplayOverlay from '../media/autoplay-overlay/component'; import logger from '/imports/startup/client/logger'; import playAndRetry from '/imports/utils/mediaElementPlayRetry'; const intlMessages = defineMessages({ screenShareLabel: { id: 'app.screenshare.screenShareLabel', description: 'screen share area element label', }, autoplayBlockedDesc: { id: 'app.media.screenshare.autoplayBlockedDesc', }, autoplayAllowLabel: { id: 'app.media.screenshare.autoplayAllowLabel', }, }); const ALLOW_FULLSCREEN = Meteor.settings.public.app.allowFullscreen; class ScreenshareComponent extends React.Component { constructor() { super(); this.state = { loaded: false, isFullscreen: false, autoplayBlocked: false, }; this.onVideoLoad = this.onVideoLoad.bind(this); this.onFullscreenChange = this.onFullscreenChange.bind(this); this.handleAllowAutoplay = this.handleAllowAutoplay.bind(this); this.handlePlayElementFailed = this.handlePlayElementFailed.bind(this); this.failedMediaElements = []; } componentDidMount() { const { presenterScreenshareHasStarted } = this.props; presenterScreenshareHasStarted(); this.screenshareContainer.addEventListener('fullscreenchange', this.onFullscreenChange); window.addEventListener('screensharePlayFailed', this.handlePlayElementFailed); } componentWillReceiveProps(nextProps) { const { isPresenter, unshareScreen, } = this.props; if (isPresenter && !nextProps.isPresenter) { unshareScreen(); } } componentWillUnmount() { const { presenterScreenshareHasEnded, unshareScreen, } = this.props; presenterScreenshareHasEnded(); unshareScreen(); this.screenshareContainer.removeEventListener('fullscreenchange', this.onFullscreenChange); window.removeEventListener('screensharePlayFailed', this.handlePlayElementFailed); } onVideoLoad() { this.setState({ loaded: true }); } onFullscreenChange() { const { isFullscreen } = this.state; const newIsFullscreen = FullscreenService.isFullScreen(this.screenshareContainer); if (isFullscreen !== newIsFullscreen) { this.setState({ isFullscreen: newIsFullscreen }); } } handleAllowAutoplay() { const { autoplayBlocked } = this.state; logger.info({ logCode: 'screenshare_autoplay_allowed', }, 'Screenshare media autoplay allowed by the user'); window.removeEventListener('screensharePlayFailed', this.handlePlayElementFailed); while (this.failedMediaElements.length) { const mediaElement = this.failedMediaElements.shift(); if (mediaElement) { const played = playAndRetry(mediaElement); if (!played) { logger.error({ logCode: 'screenshare_autoplay_handling_failed', }, 'Screenshare autoplay handling failed to play media'); } else { logger.info({ logCode: 'screenshare_viewer_media_play_success', }, 'Screenshare viewer media played successfully'); } } } if (autoplayBlocked) { this.setState({ autoplayBlocked: false }); } } handlePlayElementFailed(e) { const { mediaElement } = e.detail; const { autoplayBlocked } = this.state; e.stopPropagation(); this.failedMediaElements.push(mediaElement); if (!autoplayBlocked) { logger.info({ logCode: 'screenshare_autoplay_prompt', }, 'Prompting user for action to play screenshare media'); this.setState({ autoplayBlocked: true }); } } renderFullscreenButton() { const { intl } = this.props; const { isFullscreen } = this.state; if (!ALLOW_FULLSCREEN) return null; return ( ); } render() { const { loaded, autoplayBlocked } = this.state; const { intl } = this.props; return ( [!loaded ? (
) : null, !autoplayBlocked ? null : ( ), (
{ this.screenshareContainer = ref; }} > {loaded && this.renderFullscreenButton()}
)] ); } } export default injectIntl(ScreenshareComponent); ScreenshareComponent.propTypes = { intl: intlShape.isRequired, isPresenter: PropTypes.bool.isRequired, unshareScreen: PropTypes.func.isRequired, presenterScreenshareHasEnded: PropTypes.func.isRequired, presenterScreenshareHasStarted: PropTypes.func.isRequired, };