@@ -34,7 +34,6 @@ import type {
34
34
JitsiMeetExternalAPIConstructor ,
35
35
ExternalAPIEventCallbacks ,
36
36
JitsiMeetExternalAPI as _JitsiMeetExternalAPI ,
37
- AudioMuteStatusChangedEvent ,
38
37
LogEvent ,
39
38
VideoMuteStatusChangedEvent ,
40
39
ExternalAPIOptions as _ExternalAPIOptions ,
@@ -103,6 +102,14 @@ let widgetApi: WidgetApi | undefined;
103
102
let meetApi : _JitsiMeetExternalAPI | undefined ;
104
103
let skipOurWelcomeScreen = false ;
105
104
105
+ async function checkAudioVideoEnabled ( ) : Promise < [ audioEnabled : boolean , videoEnabled : boolean ] > {
106
+ if ( ! meetApi ) return [ false , false ] ;
107
+ const [ audioEnabled , videoEnabled ] = ( await Promise . all ( [ meetApi . isAudioMuted ( ) , meetApi . isVideoMuted ( ) ] ) ) . map (
108
+ ( muted ) => ! muted ,
109
+ ) ;
110
+ return [ audioEnabled , videoEnabled ] ;
111
+ }
112
+
106
113
const setupCompleted = ( async ( ) : Promise < string | void > => {
107
114
try {
108
115
// Queue a config.json lookup asap, so we can use it later on. We want this to be concurrent with
@@ -159,16 +166,15 @@ const setupCompleted = (async (): Promise<string | void> => {
159
166
160
167
const handleAction = (
161
168
action : WidgetApiAction ,
162
- handler : ( request : IWidgetApiRequestData ) => Promise < void > ,
169
+ handler : ( request : IWidgetApiRequestData ) => Promise < IWidgetApiResponseData | void > ,
163
170
) : void => {
164
171
widgetApi ! . on ( `action:${ action } ` , async ( ev : CustomEvent < IWidgetApiRequest > ) => {
165
172
ev . preventDefault ( ) ;
166
173
await setupCompleted ;
167
174
168
175
let response : IWidgetApiResponseData ;
169
176
try {
170
- await handler ( ev . detail . data ) ;
171
- response = { } ;
177
+ response = ( await handler ( ev . detail . data ) ) ?? { } ;
172
178
} catch ( e ) {
173
179
if ( e instanceof Error ) {
174
180
response = { error : { message : e . message } } ;
@@ -194,25 +200,26 @@ const setupCompleted = (async (): Promise<string | void> => {
194
200
meetApi ?. executeCommand ( "hangup" ) ;
195
201
}
196
202
} ) ;
197
- handleAction ( ElementWidgetActions . MuteAudio , async ( ) => {
198
- if ( meetApi && ! ( await meetApi . isAudioMuted ( ) ) ) {
199
- meetApi . executeCommand ( "toggleAudio" ) ;
203
+ handleAction ( ElementWidgetActions . DeviceMute , async ( params ) => {
204
+ if ( ! meetApi ) return ;
205
+
206
+ const [ audioEnabled , videoEnabled ] = await checkAudioVideoEnabled ( ) ;
207
+
208
+ if ( Object . keys ( params ) . length === 0 ) {
209
+ // Handle query
210
+ return {
211
+ audio_enabled : audioEnabled ,
212
+ video_enabled : videoEnabled ,
213
+ } ;
200
214
}
201
- } ) ;
202
- handleAction ( ElementWidgetActions . UnmuteAudio , async ( ) => {
203
- if ( meetApi && ( await meetApi . isAudioMuted ( ) ) ) {
215
+
216
+ if ( params . audio_enabled !== audioEnabled ) {
204
217
meetApi . executeCommand ( "toggleAudio" ) ;
205
218
}
206
- } ) ;
207
- handleAction ( ElementWidgetActions . MuteVideo , async ( ) => {
208
- if ( meetApi && ! ( await meetApi . isVideoMuted ( ) ) ) {
209
- meetApi . executeCommand ( "toggleVideo" ) ;
210
- }
211
- } ) ;
212
- handleAction ( ElementWidgetActions . UnmuteVideo , async ( ) => {
213
- if ( meetApi && ( await meetApi . isVideoMuted ( ) ) ) {
219
+ if ( params . video_enabled !== videoEnabled ) {
214
220
meetApi . executeCommand ( "toggleVideo" ) ;
215
221
}
222
+ return params ;
216
223
} ) ;
217
224
handleAction ( ElementWidgetActions . TileLayout , async ( ) => {
218
225
meetApi ?. executeCommand ( "setTileView" , true ) ;
@@ -473,7 +480,7 @@ async function joinConference(audioInput?: string | null, videoInput?: string |
473
480
meetApi . on ( "videoConferenceLeft" , onVideoConferenceLeft ) ;
474
481
meetApi . on ( "readyToClose" , closeConference as ExternalAPIEventCallbacks [ "readyToClose" ] ) ;
475
482
meetApi . on ( "errorOccurred" , onErrorOccurred ) ;
476
- meetApi . on ( "audioMuteStatusChanged" , onAudioMuteStatusChanged ) ;
483
+ meetApi . on ( "audioMuteStatusChanged" , onMuteStatusChanged ) ;
477
484
meetApi . on ( "videoMuteStatusChanged" , onVideoMuteStatusChanged ) ;
478
485
479
486
( [ "videoConferenceJoined" , "participantJoined" , "participantLeft" ] as const ) . forEach ( ( event ) => {
@@ -523,9 +530,13 @@ const onErrorOccurred = ({ error }: Parameters<ExternalAPIEventCallbacks["errorO
523
530
}
524
531
} ;
525
532
526
- const onAudioMuteStatusChanged = ( { muted } : AudioMuteStatusChangedEvent ) : void => {
527
- const action = muted ? ElementWidgetActions . MuteAudio : ElementWidgetActions . UnmuteAudio ;
528
- void widgetApi ?. transport . send ( action , { } ) ;
533
+ const onMuteStatusChanged = async ( ) : Promise < void > => {
534
+ if ( ! meetApi ) return ;
535
+ const [ audioEnabled , videoEnabled ] = await checkAudioVideoEnabled ( ) ;
536
+ void widgetApi ?. transport . send ( ElementWidgetActions . DeviceMute , {
537
+ audio_enabled : audioEnabled ,
538
+ video_enabled : videoEnabled ,
539
+ } ) ;
529
540
} ;
530
541
531
542
const onVideoMuteStatusChanged = ( { muted } : VideoMuteStatusChangedEvent ) : void => {
@@ -534,11 +545,9 @@ const onVideoMuteStatusChanged = ({ muted }: VideoMuteStatusChangedEvent): void
534
545
// hanging up, which we need to ignore by padding the timeout here,
535
546
// otherwise the React SDK will mistakenly think the user turned off
536
547
// their video by hand
537
- setTimeout ( ( ) => {
538
- if ( meetApi ) void widgetApi ?. transport . send ( ElementWidgetActions . MuteVideo , { } ) ;
539
- } , 200 ) ;
548
+ setTimeout ( ( ) => onMuteStatusChanged , 200 ) ;
540
549
} else {
541
- void widgetApi ?. transport . send ( ElementWidgetActions . UnmuteVideo , { } ) ;
550
+ void onMuteStatusChanged ( ) ;
542
551
}
543
552
} ;
544
553
0 commit comments