2026-09-13 14:14:38 -04:00
"use strict" ;
var _interopRequireDefault = require ( "@babel/runtime/helpers/interopRequireDefault" ) ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . GroupCallEventHandlerEvent = exports . GroupCallEventHandler = void 0 ;
var _defineProperty2 = _interopRequireDefault ( require ( "@babel/runtime/helpers/defineProperty" ) ) ;
var _client = require ( "../client" ) ;
var _groupCall = require ( "./groupCall" ) ;
var _roomState = require ( "../models/room-state" ) ;
var _logger = require ( "../logger" ) ;
var _event = require ( "../@types/event" ) ;
var _sync = require ( "../sync" ) ;
2026-09-12 23:57:45 -04:00
/ *
Copyright 2021 Šimon Brandner < simon . bra . ag @ gmail . com >
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2026-09-13 14:14:38 -04:00
let GroupCallEventHandlerEvent = /*#__PURE__*/ function ( GroupCallEventHandlerEvent ) {
2026-09-12 23:57:45 -04:00
GroupCallEventHandlerEvent [ "Incoming" ] = "GroupCall.incoming" ;
GroupCallEventHandlerEvent [ "Outgoing" ] = "GroupCall.outgoing" ;
GroupCallEventHandlerEvent [ "Ended" ] = "GroupCall.ended" ;
GroupCallEventHandlerEvent [ "Participants" ] = "GroupCall.participants" ;
return GroupCallEventHandlerEvent ;
} ( { } ) ;
2026-09-13 14:14:38 -04:00
exports . GroupCallEventHandlerEvent = GroupCallEventHandlerEvent ;
class GroupCallEventHandler {
2026-09-12 23:57:45 -04:00
constructor ( client ) {
2026-09-13 14:14:38 -04:00
this . client = client ;
( 0 , _defineProperty2 . default ) ( this , "groupCalls" , new Map ( ) ) ;
2026-09-12 23:57:45 -04:00
// roomId -> GroupCall
// All rooms we know about and whether we've seen a 'Room' event
// for them. The promise will be fulfilled once we've processed that
// event which means we're "up to date" on what calls are in a room
// and get
2026-09-13 14:14:38 -04:00
( 0 , _defineProperty2 . default ) ( this , "roomDeferreds" , new Map ( ) ) ;
( 0 , _defineProperty2 . default ) ( this , "onRoomsChanged" , room => {
2026-09-12 23:57:45 -04:00
this . createGroupCallForRoom ( room ) ;
} ) ;
2026-09-13 14:14:38 -04:00
( 0 , _defineProperty2 . default ) ( this , "onRoomStateChanged" , ( event , state ) => {
2026-09-12 23:57:45 -04:00
const eventType = event . getType ( ) ;
2026-09-13 14:14:38 -04:00
if ( eventType === _event . EventType . GroupCallPrefix ) {
2026-09-12 23:57:45 -04:00
const groupCallId = event . getStateKey ( ) ;
const content = event . getContent ( ) ;
const currentGroupCall = this . groupCalls . get ( state . roomId ) ;
if ( ! currentGroupCall && ! content [ "m.terminated" ] && ! event . isRedacted ( ) ) {
this . createGroupCallFromRoomStateEvent ( event ) ;
} else if ( currentGroupCall && currentGroupCall . groupCallId === groupCallId ) {
if ( content [ "m.terminated" ] || event . isRedacted ( ) ) {
currentGroupCall . terminate ( false ) ;
} else if ( content [ "m.type" ] !== currentGroupCall . type ) {
// TODO: Handle the callType changing when the room state changes
2026-09-13 14:14:38 -04:00
_logger . logger . warn ( ` GroupCallEventHandler onRoomStateChanged() currently does not support changing type (roomId= ${ state . roomId } ) ` ) ;
2026-09-12 23:57:45 -04:00
}
} else if ( currentGroupCall && currentGroupCall . groupCallId !== groupCallId ) {
// TODO: Handle new group calls and multiple group calls
2026-09-13 14:14:38 -04:00
_logger . logger . warn ( ` GroupCallEventHandler onRoomStateChanged() currently does not support multiple calls (roomId= ${ state . roomId } ) ` ) ;
2026-09-12 23:57:45 -04:00
}
}
} ) ;
}
async start ( ) {
// We wait until the client has started syncing for real.
// This is because we only support one call at a time, and want
// the latest. We therefore want the latest state of the room before
// we create a group call for the room so we can be fairly sure that
// the group call we create is really the latest one.
2026-09-13 14:14:38 -04:00
if ( this . client . getSyncState ( ) !== _sync . SyncState . Syncing ) {
_logger . logger . debug ( "GroupCallEventHandler start() waiting for client to start syncing" ) ;
2026-09-12 23:57:45 -04:00
await new Promise ( resolve => {
const onSync = ( ) => {
2026-09-13 14:14:38 -04:00
if ( this . client . getSyncState ( ) === _sync . SyncState . Syncing ) {
this . client . off ( _client . ClientEvent . Sync , onSync ) ;
2026-09-12 23:57:45 -04:00
return resolve ( ) ;
}
} ;
2026-09-13 14:14:38 -04:00
this . client . on ( _client . ClientEvent . Sync , onSync ) ;
2026-09-12 23:57:45 -04:00
} ) ;
}
const rooms = this . client . getRooms ( ) ;
for ( const room of rooms ) {
this . createGroupCallForRoom ( room ) ;
}
2026-09-13 14:14:38 -04:00
this . client . on ( _client . ClientEvent . Room , this . onRoomsChanged ) ;
this . client . on ( _roomState . RoomStateEvent . Events , this . onRoomStateChanged ) ;
2026-09-12 23:57:45 -04:00
}
stop ( ) {
2026-09-13 14:14:38 -04:00
this . client . removeListener ( _roomState . RoomStateEvent . Events , this . onRoomStateChanged ) ;
2026-09-12 23:57:45 -04:00
}
getRoomDeferred ( roomId ) {
let deferred = this . roomDeferreds . get ( roomId ) ;
if ( deferred === undefined ) {
let resolveFunc ;
deferred = {
prom : new Promise ( resolve => {
resolveFunc = resolve ;
} )
} ;
deferred . resolve = resolveFunc ;
this . roomDeferreds . set ( roomId , deferred ) ;
}
return deferred ;
}
waitUntilRoomReadyForGroupCalls ( roomId ) {
return this . getRoomDeferred ( roomId ) . prom ;
}
getGroupCallById ( groupCallId ) {
return [ ... this . groupCalls . values ( ) ] . find ( groupCall => groupCall . groupCallId === groupCallId ) ;
}
createGroupCallForRoom ( room ) {
2026-09-13 14:14:38 -04:00
const callEvents = room . currentState . getStateEvents ( _event . EventType . GroupCallPrefix ) ;
2026-09-12 23:57:45 -04:00
const sortedCallEvents = callEvents . sort ( ( a , b ) => b . getTs ( ) - a . getTs ( ) ) ;
for ( const callEvent of sortedCallEvents ) {
const content = callEvent . getContent ( ) ;
if ( content [ "m.terminated" ] || callEvent . isRedacted ( ) ) {
continue ;
}
2026-09-13 14:14:38 -04:00
_logger . logger . debug ( ` GroupCallEventHandler createGroupCallForRoom() choosing group call from possible calls (stateKey= ${ callEvent . getStateKey ( ) } , ts= ${ callEvent . getTs ( ) } , roomId= ${ room . roomId } , numOfPossibleCalls= ${ callEvents . length } ) ` ) ;
2026-09-12 23:57:45 -04:00
this . createGroupCallFromRoomStateEvent ( callEvent ) ;
break ;
}
2026-09-13 14:14:38 -04:00
_logger . logger . info ( ` GroupCallEventHandler createGroupCallForRoom() processed room (roomId= ${ room . roomId } ) ` ) ;
2026-09-12 23:57:45 -04:00
this . getRoomDeferred ( room . roomId ) . resolve ( ) ;
}
createGroupCallFromRoomStateEvent ( event ) {
const roomId = event . getRoomId ( ) ;
const content = event . getContent ( ) ;
const room = this . client . getRoom ( roomId ) ;
if ( ! room ) {
2026-09-13 14:14:38 -04:00
_logger . logger . warn ( ` GroupCallEventHandler createGroupCallFromRoomStateEvent() couldn't find room for call (roomId= ${ roomId } ) ` ) ;
2026-09-12 23:57:45 -04:00
return ;
}
const groupCallId = event . getStateKey ( ) ;
const callType = content [ "m.type" ] ;
2026-09-13 14:14:38 -04:00
if ( ! Object . values ( _groupCall . GroupCallType ) . includes ( callType ) ) {
_logger . logger . warn ( ` GroupCallEventHandler createGroupCallFromRoomStateEvent() received invalid call type (type= ${ callType } , roomId= ${ roomId } ) ` ) ;
2026-09-12 23:57:45 -04:00
return ;
}
const callIntent = content [ "m.intent" ] ;
2026-09-13 14:14:38 -04:00
if ( ! Object . values ( _groupCall . GroupCallIntent ) . includes ( callIntent ) ) {
_logger . logger . warn ( ` Received invalid group call intent (type= ${ callType } , roomId= ${ roomId } ) ` ) ;
2026-09-12 23:57:45 -04:00
return ;
}
const isPtt = Boolean ( content [ "io.element.ptt" ] ) ;
let dataChannelOptions ;
2026-09-13 14:14:38 -04:00
if ( content !== null && content !== void 0 && content . dataChannelsEnabled && content !== null && content !== void 0 && content . dataChannelOptions ) {
2026-09-12 23:57:45 -04:00
// Pull out just the dataChannelOptions we want to support.
const {
ordered ,
maxPacketLifeTime ,
maxRetransmits ,
protocol
} = content . dataChannelOptions ;
dataChannelOptions = {
ordered ,
maxPacketLifeTime ,
maxRetransmits ,
protocol
} ;
}
2026-09-13 14:14:38 -04:00
const groupCall = new _groupCall . GroupCall ( this . client , room , callType , isPtt , callIntent , groupCallId ,
2026-09-12 23:57:45 -04:00
// Because without Media section a WebRTC connection is not possible, so need a RTCDataChannel to set up a
// no media WebRTC connection anyway.
2026-09-13 14:14:38 -04:00
( content === null || content === void 0 ? void 0 : content . dataChannelsEnabled ) || this . client . isVoipWithNoMediaAllowed , dataChannelOptions , this . client . isVoipWithNoMediaAllowed ) ;
2026-09-12 23:57:45 -04:00
this . groupCalls . set ( room . roomId , groupCall ) ;
this . client . emit ( GroupCallEventHandlerEvent . Incoming , groupCall ) ;
return groupCall ;
}
}
2026-09-13 14:14:38 -04:00
exports . GroupCallEventHandler = GroupCallEventHandler ;
2026-09-12 23:57:45 -04:00
//# sourceMappingURL=groupCallEventHandler.js.map