@@ -83,11 +83,19 @@ import { CallError } from "matrix-js-sdk/src/webrtc/call";
8383import { logger } from 'matrix-js-sdk/src/logger' ;
8484import DesktopCapturerSourcePicker from "./components/views/elements/DesktopCapturerSourcePicker"
8585import { Action } from './dispatcher/actions' ;
86- import { roomForVirtualRoom , getOrCreateVirtualRoomForRoom } from './VoipUserMapper' ;
86+ import VoipUserMapper from './VoipUserMapper' ;
8787import { addManagedHybridWidget , isManagedHybridWidgetEnabled } from './widgets/ManagedHybrid' ;
8888import { randomString } from "matrix-js-sdk/src/randomstring" ;
8989
90- const CHECK_PSTN_SUPPORT_ATTEMPTS = 3 ;
90+ export const PROTOCOL_PSTN = 'm.protocol.pstn' ;
91+ export const PROTOCOL_PSTN_PREFIXED = 'im.vector.protocol.pstn' ;
92+ export const PROTOCOL_SIP_NATIVE = 'im.vector.protocol.sip_native' ;
93+ export const PROTOCOL_SIP_VIRTUAL = 'im.vector.protocol.sip_virtual' ;
94+
95+ const CHECK_PROTOCOLS_ATTEMPTS = 3 ;
96+ // Event type for room account data and room creation content used to mark rooms as virtual rooms
97+ // (and store the ID of their native room)
98+ export const VIRTUAL_ROOM_EVENT_TYPE = 'im.vector.is_virtual_room' ;
9199
92100enum AudioID {
93101 Ring = 'ringAudio' ,
@@ -96,6 +104,29 @@ enum AudioID {
96104 Busy = 'busyAudio' ,
97105}
98106
107+ interface ThirdpartyLookupResponseFields {
108+ /* eslint-disable camelcase */
109+
110+ // im.vector.sip_native
111+ virtual_mxid ?: string ;
112+ is_virtual ?: boolean ;
113+
114+ // im.vector.sip_virtual
115+ native_mxid ?: string ;
116+ is_native ?: boolean ;
117+
118+ // common
119+ lookup_success ?: boolean ;
120+
121+ /* eslint-enable camelcase */
122+ }
123+
124+ interface ThirdpartyLookupResponse {
125+ userid : string ,
126+ protocol : string ,
127+ fields : ThirdpartyLookupResponseFields ,
128+ }
129+
99130// Unlike 'CallType' in js-sdk, this one includes screen sharing
100131// (because a screen sharing call is only a screen sharing call to the caller,
101132// to the callee it's just a video call, at least as far as the current impl
@@ -126,7 +157,12 @@ export default class CallHandler {
126157 private audioPromises = new Map < AudioID , Promise < void > > ( ) ;
127158 private dispatcherRef : string = null ;
128159 private supportsPstnProtocol = null ;
160+ private pstnSupportPrefixed = null ; // True if the server only support the prefixed pstn protocol
161+ private supportsSipNativeVirtual = null ; // im.vector.protocol.sip_virtual and im.vector.protocol.sip_native
129162 private pstnSupportCheckTimer : NodeJS . Timeout ; // number actually because we're in the browser
163+ // For rooms we've been invited to, true if they're from virtual user, false if we've checked and they aren't.
164+ private invitedRoomsAreVirtual = new Map < string , boolean > ( ) ;
165+ private invitedRoomCheckInProgress = false ;
130166
131167 static sharedInstance ( ) {
132168 if ( ! window . mxCallHandler ) {
@@ -140,9 +176,9 @@ export default class CallHandler {
140176 * Gets the user-facing room associated with a call (call.roomId may be the call "virtual room"
141177 * if a voip_mxid_translate_pattern is set in the config)
142178 */
143- public static roomIdForCall ( call : MatrixCall ) {
179+ public static roomIdForCall ( call : MatrixCall ) : string {
144180 if ( ! call ) return null ;
145- return roomForVirtualRoom ( call . roomId ) || call . roomId ;
181+ return VoipUserMapper . sharedInstance ( ) . nativeRoomForVirtualRoom ( call . roomId ) || call . roomId ;
146182 }
147183
148184 start ( ) {
@@ -163,7 +199,7 @@ export default class CallHandler {
163199 MatrixClientPeg . get ( ) . on ( 'Call.incoming' , this . onCallIncoming ) ;
164200 }
165201
166- this . checkForPstnSupport ( CHECK_PSTN_SUPPORT_ATTEMPTS ) ;
202+ this . checkProtocols ( CHECK_PROTOCOLS_ATTEMPTS ) ;
167203 }
168204
169205 stop ( ) {
@@ -177,33 +213,73 @@ export default class CallHandler {
177213 }
178214 }
179215
180- private async checkForPstnSupport ( maxTries ) {
216+ private async checkProtocols ( maxTries ) {
181217 try {
182218 const protocols = await MatrixClientPeg . get ( ) . getThirdpartyProtocols ( ) ;
183- if ( protocols [ 'im.vector.protocol.pstn' ] !== undefined ) {
184- this . supportsPstnProtocol = protocols [ 'im.vector.protocol.pstn' ] ;
185- } else if ( protocols [ 'm.protocol.pstn' ] !== undefined ) {
186- this . supportsPstnProtocol = protocols [ 'm.protocol.pstn' ] ;
219+
220+ if ( protocols [ PROTOCOL_PSTN ] !== undefined ) {
221+ this . supportsPstnProtocol = Boolean ( protocols [ PROTOCOL_PSTN ] ) ;
222+ if ( this . supportsPstnProtocol ) this . pstnSupportPrefixed = false ;
223+ } else if ( protocols [ PROTOCOL_PSTN_PREFIXED ] !== undefined ) {
224+ this . supportsPstnProtocol = Boolean ( protocols [ PROTOCOL_PSTN_PREFIXED ] ) ;
225+ if ( this . supportsPstnProtocol ) this . pstnSupportPrefixed = true ;
187226 } else {
188227 this . supportsPstnProtocol = null ;
189228 }
229+
190230 dis . dispatch ( { action : Action . PstnSupportUpdated } ) ;
231+
232+ if ( protocols [ PROTOCOL_SIP_NATIVE ] !== undefined && protocols [ PROTOCOL_SIP_VIRTUAL ] !== undefined ) {
233+ this . supportsSipNativeVirtual = Boolean (
234+ protocols [ PROTOCOL_SIP_NATIVE ] && protocols [ PROTOCOL_SIP_VIRTUAL ] ,
235+ ) ;
236+ }
237+
238+ dis . dispatch ( { action : Action . VirtualRoomSupportUpdated } ) ;
191239 } catch ( e ) {
192240 if ( maxTries === 1 ) {
193- console . log ( "Failed to check for pstn protocol support and no retries remain: assuming no support" , e ) ;
241+ console . log ( "Failed to check for protocol support and no retries remain: assuming no support" , e ) ;
194242 } else {
195- console . log ( "Failed to check for pstn protocol support: will retry" , e ) ;
243+ console . log ( "Failed to check for protocol support: will retry" , e ) ;
196244 this . pstnSupportCheckTimer = setTimeout ( ( ) => {
197- this . checkForPstnSupport ( maxTries - 1 ) ;
245+ this . checkProtocols ( maxTries - 1 ) ;
198246 } , 10000 ) ;
199247 }
200248 }
201249 }
202250
203- getSupportsPstnProtocol ( ) {
251+ public getSupportsPstnProtocol ( ) {
204252 return this . supportsPstnProtocol ;
205253 }
206254
255+ public getSupportsVirtualRooms ( ) {
256+ return this . supportsPstnProtocol ;
257+ }
258+
259+ public pstnLookup ( phoneNumber : string ) : Promise < ThirdpartyLookupResponse [ ] > {
260+ return MatrixClientPeg . get ( ) . getThirdpartyUser (
261+ this . pstnSupportPrefixed ? PROTOCOL_PSTN_PREFIXED : PROTOCOL_PSTN , {
262+ 'm.id.phone' : phoneNumber ,
263+ } ,
264+ ) ;
265+ }
266+
267+ public sipVirtualLookup ( nativeMxid : string ) : Promise < ThirdpartyLookupResponse [ ] > {
268+ return MatrixClientPeg . get ( ) . getThirdpartyUser (
269+ PROTOCOL_SIP_VIRTUAL , {
270+ 'native_mxid' : nativeMxid ,
271+ } ,
272+ ) ;
273+ }
274+
275+ public sipNativeLookup ( virtualMxid : string ) : Promise < ThirdpartyLookupResponse [ ] > {
276+ return MatrixClientPeg . get ( ) . getThirdpartyUser (
277+ PROTOCOL_SIP_NATIVE , {
278+ 'virtual_mxid' : virtualMxid ,
279+ } ,
280+ ) ;
281+ }
282+
207283 private onCallIncoming = ( call ) => {
208284 // we dispatch this synchronously to make sure that the event
209285 // handlers on the call are set up immediately (so that if
@@ -550,7 +626,7 @@ export default class CallHandler {
550626 Analytics . trackEvent ( 'voip' , 'placeCall' , 'type' , type ) ;
551627 CountlyAnalytics . instance . trackStartCall ( roomId , type === PlaceCallType . Video , false ) ;
552628
553- const mappedRoomId = ( await getOrCreateVirtualRoomForRoom ( roomId ) ) || roomId ;
629+ const mappedRoomId = ( await VoipUserMapper . sharedInstance ( ) . getOrCreateVirtualRoomForRoom ( roomId ) ) || roomId ;
554630 logger . debug ( "Mapped real room " + roomId + " to room ID " + mappedRoomId ) ;
555631
556632 const call = createNewMatrixCall ( MatrixClientPeg . get ( ) , mappedRoomId ) ;
0 commit comments