123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- /* @flow */
-
- import PropTypes from 'prop-types';
- import React, { Component } from 'react';
- import { connect } from 'react-redux';
-
- import { Audio } from '../../media';
- import { Avatar } from '../../participants';
- import { Container, Text } from '../../react';
- import UIEvents from '../../../../../service/UI/UIEvents';
-
- import styles from './styles';
-
- declare var $: Object;
- declare var APP: Object;
- declare var interfaceConfig: Object;
-
- /**
- * Implements a React {@link Component} which depicts the establishment of a
- * call with a specific remote callee.
- *
- * @extends Component
- */
- class CallOverlay extends Component {
- /**
- * The (reference to the) {@link Audio} which plays/renders the audio
- * depicting the ringing phase of the call establishment represented by this
- * {@code CallOverlay}.
- */
- _audio: ?Audio
-
- _onLargeVideoAvatarVisible: Function
-
- _playAudioInterval: ?number
-
- _ringingTimeout: ?number
-
- _setAudio: Function
-
- state: {
-
- /**
- * The CSS class (name), if any, to add to this {@code CallOverlay}.
- *
- * @type {string}
- */
- className: ?string,
-
- /**
- * The indicator which determines whether this {@code CallOverlay}
- * should play/render audio to indicate the ringing phase of the
- * call establishment between the local participant and the
- * associated remote callee.
- *
- * @type {boolean}
- */
- renderAudio: boolean,
-
- /**
- * The indicator which determines whether this {@code CallOverlay}
- * is depicting the ringing phase of the call establishment between
- * the local participant and the associated remote callee or the
- * phase afterwards when the callee has not answered the call for a
- * period of time and, consequently, is considered unavailable.
- *
- * @type {boolean}
- */
- ringing: boolean
- }
-
- /**
- * {@code CallOverlay} component's property types.
- *
- * @static
- */
- static propTypes = {
- _callee: PropTypes.object
- };
-
- /**
- * Initializes a new {@code CallOverlay} instance.
- *
- * @param {Object} props - The read-only React {@link Component} props with
- * which the new instance is to be initialized.
- */
- constructor(props) {
- super(props);
-
- this.state = {
- className: undefined,
- renderAudio:
- typeof interfaceConfig !== 'object'
- || !interfaceConfig.DISABLE_RINGING,
- ringing: true
- };
-
- this._onLargeVideoAvatarVisible
- = this._onLargeVideoAvatarVisible.bind(this);
- this._setAudio = this._setAudio.bind(this);
-
- if (typeof APP === 'object') {
- APP.UI.addListener(
- UIEvents.LARGE_VIDEO_AVATAR_VISIBLE,
- this._onLargeVideoAvatarVisible);
- }
- }
-
- /**
- * Sets up timeouts such as the timeout to end the ringing phase of the call
- * establishment depicted by this {@code CallOverlay}.
- *
- * @inheritdoc
- */
- componentDidMount() {
- // Set up the timeout to end the ringing phase of the call establishment
- // depicted by this CallOverlay.
- if (this.state.ringing && !this._ringingTimeout) {
- this._ringingTimeout
- = setTimeout(
- () => {
- this._pauseAudio();
-
- this._ringingTimeout = undefined;
- this.setState({
- ringing: false
- });
- },
- 30000);
- }
-
- this._playAudio();
- }
-
- /**
- * Cleans up before this {@code Calleverlay} is unmounted and destroyed.
- *
- * @inheritdoc
- */
- componentWillUnmount() {
- this._pauseAudio();
-
- if (this._ringingTimeout) {
- clearTimeout(this._ringingTimeout);
- this._ringingTimeout = undefined;
- }
-
- if (typeof APP === 'object') {
- APP.UI.removeListener(
- UIEvents.LARGE_VIDEO_AVATAR_VISIBLE,
- this._onLargeVideoAvatarVisible);
- }
- }
-
- /**
- * Implements React's {@link Component#render()}.
- *
- * @inheritdoc
- * @returns {ReactElement}
- */
- render() {
- const { className, ringing } = this.state;
- const { avatarUrl, avatar, name } = this.props._callee;
-
- return (
- <Container
- { ...this._style('ringing', className) }
- id = 'ringOverlay'>
- <Container
- { ...this._style('ringing__content') }>
- <Text { ...this._style('ringing__text') }>
- { ringing ? 'Calling...' : '' }
- </Text>
- <Avatar
- { ...this._style('ringing__avatar') }
- uri = { avatarUrl || avatar } />
- <Container
- { ...this._style('ringing__caller-info') }>
- <Text
- { ...this._style('ringing__text') }>
- { name }
- { ringing ? '' : ' isn\'t available' }
- </Text>
- </Container>
- </Container>
- { this._renderAudio() }
- </Container>
- );
- }
-
- /**
- * Notifies this {@code CallOverlay} that the visibility of the
- * participant's avatar in the large video has changed.
- *
- * @param {boolean} largeVideoAvatarVisible - If the avatar in the large
- * video (i.e. of the participant on the stage) is visible, then
- * {@code true}; otherwise, {@code false}.
- * @private
- * @returns {void}
- */
- _onLargeVideoAvatarVisible(largeVideoAvatarVisible: boolean) {
- this.setState({
- className: largeVideoAvatarVisible ? 'solidBG' : undefined
- });
- }
-
- /**
- * Stops the playback of the audio which represents the ringing phase of the
- * call establishment depicted by this {@code CallOverlay}.
- *
- * @private
- * @returns {void}
- */
- _pauseAudio() {
- const audio = this._audio;
-
- if (audio) {
- audio.pause();
- }
- if (this._playAudioInterval) {
- clearInterval(this._playAudioInterval);
- this._playAudioInterval = undefined;
- }
- }
-
- /**
- * Starts the playback of the audio which represents the ringing phase of
- * the call establishment depicted by this {@code CallOverlay}.
- *
- * @private
- * @returns {void}
- */
- _playAudio() {
- if (this._audio) {
- this._audio.play();
- if (!this._playAudioInterval) {
- this._playAudioInterval
- = setInterval(() => this._playAudio(), 5000);
- }
- }
- }
-
- /**
- * Renders an audio element to represent the ringing phase of the call
- * establishment represented by this {@code CallOverlay}.
- *
- * @private
- * @returns {ReactElement}
- */
- _renderAudio() {
- if (this.state.renderAudio && this.state.ringing) {
- return (
- <Audio
- ref = { this._setAudio }
- src = './sounds/ring.ogg' />
- );
- }
-
- return null;
- }
-
- /**
- * Sets the (reference to the) {@link Audio} which renders the ringing phase
- * of the call establishment represented by this {@code CallOverlay}.
- *
- * @param {Audio} audio - The (reference to the) {@code Audio} which
- * plays/renders the audio depicting the ringing phase of the call
- * establishment represented by this {@code CallOverlay}.
- * @private
- * @returns {void}
- */
- _setAudio(audio) {
- this._audio = audio;
- }
-
- /**
- * Attempts to convert specified CSS class names into React
- * {@link Component} props {@code style} or {@code className}.
- *
- * @param {Array<string>} classNames - The CSS class names to convert
- * into React {@code Component} props {@code style} or {@code className}.
- * @returns {{
- * className: string,
- * style: Object
- * }}
- */
- _style(...classNames: Array<?string>) {
- let className = '';
- let style;
-
- for (const aClassName of classNames) {
- if (aClassName) {
- // Attemp to convert aClassName into style.
- if (styles && aClassName in styles) {
- // React Native will accept an Array as the value of the
- // style prop. However, I do not know about React.
- style = {
- ...style,
- ...styles[aClassName]
- };
- } else {
- // Otherwise, leave it as className.
- className += aClassName;
- }
- }
- }
-
- // Choose which of the className and/or style props has a value and,
- // consequently, must be returned.
- const props = {};
-
- if (className) {
- props.className = className;
- }
- if (style) {
- props.style = style;
- }
-
- return props;
- }
- }
-
- /**
- * Maps (parts of) the redux state to {@code CallOverlay}'s props.
- *
- * @param {Object} state - The redux state.
- * @private
- * @returns {{
- * _callee: Object
- * }}
- */
- function _mapStateToProps(state) {
- return {
- /**
- *
- * @private
- * @type {Object}
- */
- _callee: state['features/base/jwt'].callee
- };
- }
-
- export default connect(_mapStateToProps)(CallOverlay);
|