fix(large-video): do not show avatar if no url (#3871)

* fix(large-video): do not show avatar if no url

By default the large video dominant speaker avatar
has an empty src, which will result in a broken
image displaying. There is also disconnect with
non-react code trying to set an undefined src.
To prevent such until local avatar generation
work is done in the future, just don't show the
avatar.

* fix(conference): set the room instance earlier

Set the room instance on APP.conference before triggering
a redux update of the conference being set,, because
middleware can then fire and call methods on APP.conference
that depend on the room being set.

* get local participant directly from store instead of from global
This commit is contained in:
virtuacoplenny 2019-02-06 19:19:02 -08:00 committed by GitHub
parent f77e1dc591
commit b7133f5717
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 13 deletions

View File

@ -1237,6 +1237,7 @@ export default {
= connection.initJitsiConference( = connection.initJitsiConference(
APP.conference.roomName, APP.conference.roomName,
this._getConferenceOptions()); this._getConferenceOptions());
APP.store.dispatch(conferenceWillJoin(room)); APP.store.dispatch(conferenceWillJoin(room));
this._setLocalAudioVideoStreams(localTracks); this._setLocalAudioVideoStreams(localTracks);
this._room = room; // FIXME do not use this this._room = room; // FIXME do not use this

View File

@ -496,18 +496,22 @@
display:none !important; display:none !important;
} }
#dominantSpeakerAvatarContainer,
#dominantSpeakerAvatar, #dominantSpeakerAvatar,
.dynamic-shadow { .dynamic-shadow {
width: 200px; width: 200px;
height: 200px; height: 200px;
} }
#dominantSpeakerAvatar { #dominantSpeakerAvatarContainer {
top: 50px; top: 50px;
margin: auto; margin: auto;
position: relative; position: relative;
border-radius: 100px; border-radius: 100px;
overflow: hidden;
visibility: inherit; visibility: inherit;
}
#dominantSpeakerAvatar {
background-color: #000000; background-color: #000000;
} }

View File

@ -6,6 +6,10 @@ import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { i18next } from '../../../react/features/base/i18n'; import { i18next } from '../../../react/features/base/i18n';
import {
Avatar,
getAvatarURLByParticipantId
} from '../../../react/features/base/participants';
import { PresenceLabel } from '../../../react/features/presence-status'; import { PresenceLabel } from '../../../react/features/presence-status';
/* eslint-enable no-unused-vars */ /* eslint-enable no-unused-vars */
@ -14,9 +18,6 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
import { import {
JitsiParticipantConnectionStatus JitsiParticipantConnectionStatus
} from '../../../react/features/base/lib-jitsi-meet'; } from '../../../react/features/base/lib-jitsi-meet';
import {
getAvatarURLByParticipantId
} from '../../../react/features/base/participants';
import { import {
updateKnownLargeVideoResolution updateKnownLargeVideoResolution
} from '../../../react/features/large-video'; } from '../../../react/features/large-video';
@ -95,6 +96,9 @@ export default class LargeVideoManager {
= this._onVideoResolutionUpdate.bind(this); = this._onVideoResolutionUpdate.bind(this);
this.videoContainer.addResizeListener(this._onVideoResolutionUpdate); this.videoContainer.addResizeListener(this._onVideoResolutionUpdate);
this._dominantSpeakerAvatarContainer
= document.getElementById('dominantSpeakerAvatarContainer');
} }
/** /**
@ -109,6 +113,8 @@ export default class LargeVideoManager {
this.removePresenceLabel(); this.removePresenceLabel();
ReactDOM.unmountComponentAtNode(this._dominantSpeakerAvatarContainer);
this.$container.css({ display: 'none' }); this.$container.css({ display: 'none' });
} }
@ -394,7 +400,17 @@ export default class LargeVideoManager {
* Updates the src of the dominant speaker avatar * Updates the src of the dominant speaker avatar
*/ */
updateAvatar(avatarUrl) { updateAvatar(avatarUrl) {
$('#dominantSpeakerAvatar').attr('src', avatarUrl); if (avatarUrl) {
ReactDOM.render(
<Avatar
id = "dominantSpeakerAvatar"
uri = { avatarUrl } />,
this._dominantSpeakerAvatarContainer
);
} else {
ReactDOM.unmountComponentAtNode(
this._dominantSpeakerAvatarContainer);
}
} }
/** /**

View File

@ -265,7 +265,7 @@ export class VideoContainer extends LargeContainer {
*/ */
this.$wrapperParent = this.$wrapper.parent(); this.$wrapperParent = this.$wrapper.parent();
this.avatarHeight = $('#dominantSpeakerAvatar').height(); this.avatarHeight = $('#dominantSpeakerAvatarContainer').height();
const onPlayingCallback = function(event) { const onPlayingCallback = function(event) {
if (typeof resizeContainer === 'function') { if (typeof resizeContainer === 'function') {
@ -408,7 +408,7 @@ export class VideoContainer extends LargeContainer {
*/ */
_positionParticipantStatus($element) { _positionParticipantStatus($element) {
if (this.avatarDisplayed) { if (this.avatarDisplayed) {
const $avatarImage = $('#dominantSpeakerAvatar'); const $avatarImage = $('#dominantSpeakerAvatarContainer');
$element.css( $element.css(
'top', 'top',

View File

@ -10,6 +10,7 @@ import {
} from '../../../react/features/base/lib-jitsi-meet'; } from '../../../react/features/base/lib-jitsi-meet';
import { VIDEO_TYPE } from '../../../react/features/base/media'; import { VIDEO_TYPE } from '../../../react/features/base/media';
import { import {
getLocalParticipant as getLocalParticipantFromStore,
getPinnedParticipant, getPinnedParticipant,
pinParticipant pinParticipant
} from '../../../react/features/base/participants'; } from '../../../react/features/base/participants';
@ -75,6 +76,16 @@ function getAllThumbnails() {
]; ];
} }
/**
* Private helper to get the redux representation of the local participant.
*
* @private
* @returns {Object}
*/
function getLocalParticipant() {
return getLocalParticipantFromStore(APP.store.getState());
}
/** /**
* Returns the user ID of the remote participant that is current the dominant * Returns the user ID of the remote participant that is current the dominant
* speaker. * speaker.
@ -181,7 +192,7 @@ const VideoLayout = {
}, },
changeLocalVideo(stream) { changeLocalVideo(stream) {
const localId = APP.conference.getMyUserId(); const localId = getLocalParticipant().id;
this.onVideoTypeChanged(localId, stream.videoType); this.onVideoTypeChanged(localId, stream.videoType);
@ -198,7 +209,7 @@ const VideoLayout = {
*/ */
mucJoined() { mucJoined() {
if (largeVideo && !largeVideo.id) { if (largeVideo && !largeVideo.id) {
this.updateLargeVideo(APP.conference.getMyUserId(), true); this.updateLargeVideo(getLocalParticipant().id, true);
} }
// FIXME: replace this call with a generic update call once SmallVideo // FIXME: replace this call with a generic update call once SmallVideo
@ -302,7 +313,7 @@ const VideoLayout = {
// Go with local video // Go with local video
logger.info('Fallback to local video...'); logger.info('Fallback to local video...');
const id = APP.conference.getMyUserId(); const { id } = getLocalParticipant();
logger.info(`electLastVisibleVideo: ${id}`); logger.info(`electLastVisibleVideo: ${id}`);

View File

@ -34,9 +34,7 @@ export default class LargeVideo extends Component<{}> {
<div id = 'dominantSpeaker'> <div id = 'dominantSpeaker'>
<div className = 'dynamic-shadow' /> <div className = 'dynamic-shadow' />
<img <div id = 'dominantSpeakerAvatarContainer' />
id = 'dominantSpeakerAvatar'
src = '' />
</div> </div>
<div id = 'remotePresenceMessage' /> <div id = 'remotePresenceMessage' />
<span id = 'remoteConnectionMessage' /> <span id = 'remoteConnectionMessage' />