diff --git a/res/css/views/voip/_CallView.scss b/res/css/views/voip/_CallView.scss index 63ca91267f3..aa0aa4e2a67 100644 --- a/res/css/views/voip/_CallView.scss +++ b/res/css/views/voip/_CallView.scss @@ -74,9 +74,9 @@ limitations under the License. > .mx_VideoFeed { width: 100%; height: 100%; + border-width: 0 !important; // Override mx_VideoFeed_speaking &.mx_VideoFeed_voice { - background-color: $inverted-bg-color; display: flex; justify-content: center; align-items: center; diff --git a/res/css/views/voip/_CallViewSidebar.scss b/res/css/views/voip/_CallViewSidebar.scss index dbadc220282..fd9c76defcb 100644 --- a/res/css/views/voip/_CallViewSidebar.scss +++ b/res/css/views/voip/_CallViewSidebar.scss @@ -33,10 +33,9 @@ limitations under the License. > .mx_VideoFeed { width: 100%; + border-radius: 4px; &.mx_VideoFeed_voice { - border-radius: 4px; - display: flex; align-items: center; justify-content: center; diff --git a/res/css/views/voip/_VideoFeed.scss b/res/css/views/voip/_VideoFeed.scss index 7a8d39dfe31..1f17a546928 100644 --- a/res/css/views/voip/_VideoFeed.scss +++ b/res/css/views/voip/_VideoFeed.scss @@ -17,12 +17,23 @@ limitations under the License. .mx_VideoFeed { overflow: hidden; position: relative; + box-sizing: border-box; + border: transparent 2px solid; + display: flex; &.mx_VideoFeed_voice { background-color: $inverted-bg-color; aspect-ratio: 16 / 9; } + &.mx_VideoFeed_speaking { + border: $accent-color 2px solid; + + .mx_VideoFeed_video { + border-radius: 0; + } + } + .mx_VideoFeed_video { width: 100%; background-color: transparent; diff --git a/src/components/views/voip/VideoFeed.tsx b/src/components/views/voip/VideoFeed.tsx index 4607b750eba..13461c35918 100644 --- a/src/components/views/voip/VideoFeed.tsx +++ b/src/components/views/voip/VideoFeed.tsx @@ -45,6 +45,7 @@ interface IProps { interface IState { audioMuted: boolean; videoMuted: boolean; + speaking: boolean; } @replaceableComponent("views.voip.VideoFeed") @@ -57,6 +58,7 @@ export default class VideoFeed extends React.PureComponent { this.state = { audioMuted: this.props.feed.isAudioMuted(), videoMuted: this.props.feed.isVideoMuted(), + speaking: false, }; } @@ -103,11 +105,19 @@ export default class VideoFeed extends React.PureComponent { if (oldFeed) { this.props.feed.removeListener(CallFeedEvent.NewStream, this.onNewStream); this.props.feed.removeListener(CallFeedEvent.MuteStateChanged, this.onMuteStateChanged); + if (this.props.feed.purpose === SDPStreamMetadataPurpose.Usermedia) { + this.props.feed.removeListener(CallFeedEvent.Speaking, this.onSpeaking); + this.props.feed.measureVolumeActivity(false); + } this.stopMedia(); } if (newFeed) { this.props.feed.addListener(CallFeedEvent.NewStream, this.onNewStream); this.props.feed.addListener(CallFeedEvent.MuteStateChanged, this.onMuteStateChanged); + if (this.props.feed.purpose === SDPStreamMetadataPurpose.Usermedia) { + this.props.feed.addListener(CallFeedEvent.Speaking, this.onSpeaking); + this.props.feed.measureVolumeActivity(true); + } this.playMedia(); } } @@ -162,6 +172,10 @@ export default class VideoFeed extends React.PureComponent { }); }; + private onSpeaking = (speaking: boolean): void => { + this.setState({ speaking }); + }; + private onResize = (e) => { if (this.props.onResize && !this.props.feed.isLocal()) { this.props.onResize(e); @@ -173,6 +187,7 @@ export default class VideoFeed extends React.PureComponent { const wrapperClasses = classnames("mx_VideoFeed", { mx_VideoFeed_voice: this.state.videoMuted, + mx_VideoFeed_speaking: this.state.speaking, }); const micIconClasses = classnames("mx_VideoFeed_mic", { mx_VideoFeed_mic_muted: this.state.audioMuted,