@@ -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 ( ) } >
0 commit comments