Add a speaking indicator
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>pull/21833/head
parent
5a1633d53c
commit
abab31c33b
|
@ -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;
|
||||
|
|
|
@ -17,12 +17,17 @@ limitations under the License.
|
|||
.mx_VideoFeed {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.mx_VideoFeed_voice {
|
||||
background-color: $inverted-bg-color;
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
|
||||
&.mx_VideoFeed_speaking {
|
||||
border: $accent-color 2px solid;
|
||||
}
|
||||
|
||||
.mx_VideoFeed_video {
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
|
|
|
@ -24,6 +24,8 @@ import MemberAvatar from "../avatars/MemberAvatar";
|
|||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { SDPStreamMetadataPurpose } from 'matrix-js-sdk/src/webrtc/callEventTypes';
|
||||
|
||||
const SPEAKING_THRESHOLD = -60;
|
||||
|
||||
interface IProps {
|
||||
call: MatrixCall;
|
||||
|
||||
|
@ -45,6 +47,7 @@ interface IProps {
|
|||
interface IState {
|
||||
audioMuted: boolean;
|
||||
videoMuted: boolean;
|
||||
speaking: boolean;
|
||||
}
|
||||
|
||||
@replaceableComponent("views.voip.VideoFeed")
|
||||
|
@ -57,6 +60,7 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
|
|||
this.state = {
|
||||
audioMuted: this.props.feed.isAudioMuted(),
|
||||
videoMuted: this.props.feed.isVideoMuted(),
|
||||
speaking: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -103,11 +107,19 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
|
|||
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.VolumeChanged, this.onVolumeChanged);
|
||||
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.VolumeChanged, this.onVolumeChanged);
|
||||
this.props.feed.measureVolumeActivity(true);
|
||||
}
|
||||
this.playMedia();
|
||||
}
|
||||
}
|
||||
|
@ -162,6 +174,10 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private onVolumeChanged = (volume: number): void => {
|
||||
this.setState({ speaking: volume > SPEAKING_THRESHOLD });
|
||||
};
|
||||
|
||||
private onResize = (e) => {
|
||||
if (this.props.onResize && !this.props.feed.isLocal()) {
|
||||
this.props.onResize(e);
|
||||
|
@ -173,6 +189,7 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
|
|||
|
||||
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,
|
||||
|
|
Loading…
Reference in New Issue