Skip to content

Commit 9445798

Browse files
committed
Hard mute feature support to sample app
1 parent a0eefbf commit 9445798

File tree

2 files changed

+63
-17
lines changed

2 files changed

+63
-17
lines changed

Project/src/MakeCall/CallCard.js

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export default class CallCard extends React.Component {
4141
this.raiseHandFeature = this.call.feature(Features.RaiseHand);
4242
this.capabilitiesFeature = this.call.feature(Features.Capabilities);
4343
this.capabilities = this.capabilitiesFeature.capabilities;
44+
this.mediaAccessCallFeature = this.call.feature(Features.MediaAccess);
4445
if (Features.RealTimeText) {
4546
this.realTimeTextFeature = this.call.feature(Features.RealTimeText);
4647
}
@@ -71,6 +72,8 @@ export default class CallCard extends React.Component {
7172
canSpotlight: this.capabilities.spotlightParticipant?.isPresent || this.capabilities.spotlightParticipant?.reason === 'FeatureNotSupported',
7273
canMuteOthers: this.capabilities.muteOthers?.isPresent || this.capabilities.muteOthers?.reason === 'FeatureNotSupported',
7374
canReact: this.capabilities.useReactions?.isPresent || this.capabilities.useReactions?.reason === 'FeatureNotSupported',
75+
canForbidOthersAudio: this.capabilities.forbidOthersAudio?.isPresent || this.capabilities.forbidOthersAudio?.reason === 'FeatureNotSupported',
76+
canForbidOthersVideo: this.capabilities.forbidOthersVideo?.isPresent || this.capabilities.forbidOthersVideo?.reason === 'FeatureNotSupported',
7477
videoOn: this.call.isLocalVideoStarted,
7578
screenSharingOn: this.call.isScreenSharingOn,
7679
micMuted: this.call.isMuted,
@@ -109,7 +112,8 @@ export default class CallCard extends React.Component {
109112
pptLiveActive: false,
110113
isRecordingActive: false,
111114
isTranscriptionActive: false,
112-
lobbyParticipantsCount: this.lobby?.participants.length
115+
lobbyParticipantsCount: this.lobby?.participants.length,
116+
mediaAccessMap: Map
113117
};
114118
this.selectedRemoteParticipants = new Set();
115119
this.dataChannelRef = React.createRef();
@@ -150,7 +154,8 @@ export default class CallCard extends React.Component {
150154
this.call.feature(Features.PPTLive).off('isActiveChanged', this.pptLiveChangedHandler);
151155
}
152156
this.dominantSpeakersFeature.off('dominantSpeakersChanged', this.dominantSpeakersChanged);
153-
}
157+
this.mediaAccessCallFeature.off('mediaAccessChanged', this.mediaAccessChangedHandler);
158+
}
154159

155160
componentDidMount() {
156161
if (this.call) {
@@ -480,6 +485,7 @@ export default class CallCard extends React.Component {
480485
this.transcriptionFeature.on('isTranscriptionActiveChanged', this.isTranscriptionActiveChangedHandler);
481486
this.lobby?.on('lobbyParticipantsUpdated', this.lobbyParticipantsUpdatedHandler);
482487
this.realTimeTextFeature?.on('realTimeTextReceived', this.realTimeTextReceivedHandler);
488+
this.mediaAccessCallFeature.on('mediaAccessChanged', this.mediaAccessChangedHandler);
483489
}
484490
}
485491

@@ -541,6 +547,15 @@ export default class CallCard extends React.Component {
541547
this.identifier, this.spotlightFeature.getSpotlightedParticipants())})
542548
}
543549

550+
mediaAccessChangedHandler = (event) => {
551+
const mediaAccessMap = new Map();
552+
event.mediaAccesses.forEach((ma) => {
553+
mediaAccessMap.set(ma.participant.rawId, ma);
554+
});
555+
556+
this.setState({mediaAccessMap});
557+
}
558+
544559
isRecordingActiveChangedHandler = (event) => {
545560
this.setState({ isRecordingActive: this.recordingFeature.isRecordingActive })
546561
}
@@ -1240,6 +1255,7 @@ export default class CallCard extends React.Component {
12401255
render() {
12411256
const emojis = ['👍', '❤️', '😂', '👏', '😲'];
12421257
const streamCount = this.state.allRemoteParticipantStreams.length;
1258+
const mediaAccessMap = this.state.mediaAccessMap;
12431259
return (
12441260
<div className="ms-Grid mt-2">
12451261
<div className="ms-Grid-row">
@@ -1305,18 +1321,19 @@ export default class CallCard extends React.Component {
13051321
<p>No other participants currently in the call</p>
13061322
}
13071323
<ul className="p-0 m-0">
1308-
{
1309-
this.state.remoteParticipants.map(remoteParticipant =>
1310-
<RemoteParticipantCard
1324+
{this.state.remoteParticipants.map(remoteParticipant => {
1325+
const participantMediaAccess = mediaAccessMap?.get(remoteParticipant.identifier.rawId);
1326+
return ( <RemoteParticipantCard
13111327
key={`${utils.getIdentifierText(remoteParticipant.identifier)}`}
13121328
remoteParticipant={remoteParticipant}
13131329
call={this.call}
13141330
menuOptionsHandler={this.getParticipantMenuCallBacks()}
13151331
onSelectionChanged={(identifier, isChecked) => this.remoteParticipantSelectionChanged(identifier, isChecked)}
13161332
capabilitiesFeature={this.capabilitiesFeature}
1317-
/>
1318-
)
1319-
}
1333+
mediaAccess={participantMediaAccess}
1334+
/>);
1335+
})}
1336+
13201337
</ul>
13211338

13221339
</div>
@@ -1363,30 +1380,37 @@ export default class CallCard extends React.Component {
13631380
<div className="ms-Grid-row">
13641381
<div className="text-center">
13651382
<span className="in-call-button"
1366-
title={`Turn your video ${this.state.videoOn ? 'off' : 'on'}`}
1383+
title = {`${this.state.canOnVideo ? (this.state.videoOn ? 'Turn your video off' : 'Turn your video on') : 'Video is disabled'}`}
13671384
variant="secondary"
13681385
onClick={() => this.handleVideoOnOff()}>
13691386
{
13701387
this.state.canOnVideo && this.state.videoOn &&
13711388
<Icon iconName="Video" />
13721389
}
13731390
{
1374-
(!this.state.canOnVideo || !this.state.videoOn) &&
1391+
(this.state.canOnVideo || !this.state.videoOn) &&
1392+
<Icon iconName="VideoOff2" />
1393+
}
1394+
{
1395+
(!this.state.canOnVideo) &&
13751396
<Icon iconName="VideoOff" />
13761397
}
13771398
</span>
13781399
<span className="in-call-button"
1379-
title={`${this.state.micMuted ? 'Unmute' : 'Mute'} your microphone`}
1400+
title={`${this.state.canUnMuteMic ? (this.state.micMuted ? 'Unmute your microphone' : 'Mute your microphone') : 'Microphone is disabled'}`}
13801401
variant="secondary"
13811402
onClick={() => this.handleMicOnOff()}>
13821403
{
13831404
this.state.canUnMuteMic && !this.state.micMuted &&
13841405
<Icon iconName="Microphone" />
13851406
}
13861407
{
1387-
(!this.state.canUnMuteMic || this.state.micMuted) &&
1408+
(this.state.canUnMuteMic && this.state.micMuted) &&
13881409
<Icon iconName="MicOff2" />
13891410
}
1411+
{
1412+
!this.state.canUnMuteMic && <Icon iconName="MicOff" />
1413+
}
13901414
</span>
13911415
<span className="in-call-button"
13921416
onClick={() => this.call.hangUp()}>

Project/src/MakeCall/RemoteParticipantCard.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export default class RemoteParticipantCard extends React.Component {
2626
this.capabilitiesFeature = props.capabilitiesFeature;
2727
this.capabilities = this.capabilitiesFeature.capabilities;
2828
this.menuOptionsHandler= props.menuOptionsHandler;
29+
this.mediaAccess = props.mediaAccess;
2930
this.state = {
3031
isSpeaking: this.remoteParticipant.isSpeaking,
3132
state: this.remoteParticipant.state,
@@ -36,6 +37,7 @@ export default class RemoteParticipantCard extends React.Component {
3637
isSpotlighted: utils.isParticipantHandRaised(this.remoteParticipant.identifier, this.spotlightFeature.getSpotlightedParticipants()),
3738
canManageLobby: this.capabilities.manageLobby?.isPresent || this.capabilities.manageLobby?.reason === 'FeatureNotSupported',
3839
canMuteOthers: this.capabilities.muteOthers?.isPresent || this.capabilities.muteOthers?.reason === 'FeatureNotSupported',
40+
mediaAccess: this.mediaAccess
3941
};
4042
}
4143

@@ -52,6 +54,12 @@ export default class RemoteParticipantCard extends React.Component {
5254
}
5355
}
5456

57+
componentDidUpdate(prevProps) {
58+
if (prevProps.mediaAccess !== this.props.mediaAccess) {
59+
this.setState({ mediaAccess: this.props.mediaAccess });
60+
}
61+
}
62+
5563
componentDidMount() {
5664
this.remoteParticipant.on('isMutedChanged', () => {
5765
this.setState({ isMuted: this.remoteParticipant.isMuted });
@@ -100,6 +108,7 @@ export default class RemoteParticipantCard extends React.Component {
100108
}
101109
}
102110
});
111+
this.setState({ mediaAccess: this.props.mediaAccess });
103112
}
104113

105114
handleRemoveParticipant(e, identifier) {
@@ -189,11 +198,24 @@ export default class RemoteParticipantCard extends React.Component {
189198
</div>
190199
</div>
191200
<div className="inline-flex align-items-center ml-5">
192-
<div className="in-call-button inline-block"
193-
title={`${this.state.isMuted ? 'Participant is muted': ``}`}
194-
onClick={e => this.handleMuteParticipant(e, this.remoteParticipant)}>
195-
<Icon iconName={this.state.isMuted ? "MicOff2" : "Microphone"}/>
196-
</div>
201+
{
202+
this.state.mediaAccess?.isVideoPermitted === false ? <div className="in-call-button inline-block"
203+
title={`${this.state.isMuted ? 'Participant camera disabled': ``}`}
204+
disabled={true}>
205+
<Icon iconName={this.state.isMuted ? "VideoOff" : "Video"}/>
206+
</div> : undefined
207+
}
208+
{
209+
this.state.mediaAccess?.isAudioPermitted === false ? <div className="in-call-button inline-block"
210+
title={`${this.state.isMuted ? 'Participant mic disabled': ``}`}
211+
disabled={true}>
212+
<Icon iconName={this.state.isMuted ? "MicOff" : "Microphone"}/>
213+
</div> : <div className="in-call-button inline-block"
214+
title={`${this.state.isMuted ? 'Participant is muted': ``}`}
215+
onClick={e => this.handleMuteParticipant(e, this.remoteParticipant)}>
216+
<Icon iconName={this.state.isMuted ? "MicOff2" : "Microphone"}/>
217+
</div>
218+
}
197219
{
198220
!(isPhoneNumberIdentifier(this.remoteParticipant.identifier) || isUnknownIdentifier(this.remoteParticipant.identifier)) &&
199221
<div className="in-call-button inline-block"

0 commit comments

Comments
 (0)