diff --git a/.changeset/old-readers-battle.md b/.changeset/old-readers-battle.md new file mode 100644 index 0000000000000..fb00619ef9325 --- /dev/null +++ b/.changeset/old-readers-battle.md @@ -0,0 +1,8 @@ +--- +'@rocket.chat/core-typings': patch +'@rocket.chat/ui-voip': patch +'@rocket.chat/i18n': patch +'@rocket.chat/meteor': patch +--- + +Fixes an issue where Voice Calls were unable to gather Ice Servers diff --git a/apps/meteor/ee/server/settings/voip.ts b/apps/meteor/ee/server/settings/voip.ts index e63fc1f13df26..50f6e4dbafe95 100644 --- a/apps/meteor/ee/server/settings/voip.ts +++ b/apps/meteor/ee/server/settings/voip.ts @@ -8,6 +8,8 @@ export function addSettings(): Promise { modules: ['teams-voip'], }, async function () { + const enableQuery = { _id: 'VoIP_TeamCollab_Enabled', value: true }; + await this.add('VoIP_TeamCollab_Enabled', false, { type: 'boolean', public: true, @@ -19,30 +21,49 @@ export function addSettings(): Promise { type: 'string', public: true, invalidValue: '', + enableQuery, }); await this.add('VoIP_TeamCollab_FreeSwitch_Port', 8021, { type: 'int', public: true, invalidValue: 8021, + enableQuery, }); await this.add('VoIP_TeamCollab_FreeSwitch_Password', '', { type: 'password', secret: true, invalidValue: '', + enableQuery, }); await this.add('VoIP_TeamCollab_FreeSwitch_Timeout', 3000, { type: 'int', public: true, invalidValue: 3000, + enableQuery, }); await this.add('VoIP_TeamCollab_FreeSwitch_WebSocket_Path', '', { type: 'string', public: true, invalidValue: '', + enableQuery, + }); + + await this.add('VoIP_TeamCollab_Ice_Servers', 'stun:stun.l.google.com:19302', { + type: 'string', + public: true, + invalidValue: '', + enableQuery, + }); + + await this.add('VoIP_TeamCollab_Ice_Gathering_Timeout', 5000, { + type: 'int', + public: true, + invalidValue: 5000, + enableQuery, }); }, ); diff --git a/packages/core-typings/src/voip/VoIPUserConfiguration.ts b/packages/core-typings/src/voip/VoIPUserConfiguration.ts index 01bca0a5409cb..7bade79310cad 100644 --- a/packages/core-typings/src/voip/VoIPUserConfiguration.ts +++ b/packages/core-typings/src/voip/VoIPUserConfiguration.ts @@ -45,6 +45,12 @@ export interface VoIPUserConfiguration { * @defaultValue undefined */ enableKeepAliveUsingOptionsForUnstableNetworks: boolean; + + /** + * Time to wait for Ice Gathering to complete + * @defaultValue 5000 + */ + iceGatheringTimeout?: number; } export interface IMediaStreamRenderer { diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 4e5cc01e43fbd..d3fb8e9457146 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -6270,6 +6270,10 @@ "VoIP_TeamCollab_FreeSwitch_Timeout": "FreeSwitch Request Timeout", "VoIP_TeamCollab_FreeSwitch_WebSocket_Path": "WebSocket Path", "VoIP_TeamCollab_Beta_Alert": "This feature is currently in Beta, please report any issues to Rocket.Chat support", + "VoIP_TeamCollab_Ice_Servers": "Ice Servers", + "VoIP_TeamCollab_Ice_Servers_Description": "A list of Ice Servers (STUN and/or TURN), separated by comma. \n Username, password and port are allowed in the format `username:password@stun:host:port` or `username:password@turn:host:port`. \n Both username and password may be html-encoded.", + "VoIP_TeamCollab_Ice_Gathering_Timeout": "Ice Gathering Timeout", + "VoIP_TeamCollab_Ice_Gathering_Timeout_Description": "Time to wait for Ice Gathering to complete before sending. Low values may prevent Ice Servers from being used, while high values may delay the start of VoIP calls if an invalid Ice Server is specified.", "VoIP_Toggle": "Enable/Disable VoIP", "Chat_opened_by_visitor": "Chat opened by the visitor", "Waiting_for_answer": "Waiting for answer", diff --git a/packages/ui-voip/src/hooks/useWebRtcServers.ts b/packages/ui-voip/src/hooks/useIceServers.ts similarity index 77% rename from packages/ui-voip/src/hooks/useWebRtcServers.ts rename to packages/ui-voip/src/hooks/useIceServers.ts index 9753098c0a659..1c32343a9246a 100644 --- a/packages/ui-voip/src/hooks/useWebRtcServers.ts +++ b/packages/ui-voip/src/hooks/useIceServers.ts @@ -4,8 +4,8 @@ import { useMemo } from 'react'; import type { IceServer } from '../definitions'; import { parseStringToIceServers } from '../utils/parseStringToIceServers'; -export const useWebRtcServers = (): IceServer[] => { - const servers = useSetting('WebRTC_Servers'); +export const useIceServers = (): IceServer[] => { + const servers = useSetting('VoIP_TeamCollab_Ice_Servers'); return useMemo(() => { if (typeof servers !== 'string' || !servers.trim()) { diff --git a/packages/ui-voip/src/hooks/useVoipClient.tsx b/packages/ui-voip/src/hooks/useVoipClient.tsx index 589f76d7952c0..fdda0587b7d52 100644 --- a/packages/ui-voip/src/hooks/useVoipClient.tsx +++ b/packages/ui-voip/src/hooks/useVoipClient.tsx @@ -1,8 +1,8 @@ -import { useUser, useEndpoint } from '@rocket.chat/ui-contexts'; +import { useUser, useEndpoint, useSetting } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import { useEffect, useRef } from 'react'; -import { useWebRtcServers } from './useWebRtcServers'; +import { useIceServers } from './useIceServers'; import VoipClient from '../lib/VoipClient'; type VoipClientParams = { @@ -20,8 +20,9 @@ export const useVoipClient = ({ enabled = true, autoRegister = true }: VoipClien const voipClientRef = useRef(null); const getRegistrationInfo = useEndpoint('GET', '/v1/voip-freeswitch.extension.getRegistrationInfoByUserId'); + const iceGatheringTimeout = useSetting('VoIP_TeamCollab_Ice_Gathering_Timeout', 5000); - const iceServers = useWebRtcServers(); + const iceServers = useIceServers(); const { data: voipClient, error } = useQuery({ queryKey: ['voip-client', enabled, userId, iceServers], @@ -59,6 +60,7 @@ export const useVoipClient = ({ enabled = true, autoRegister = true }: VoipClien webSocketURI: websocketPath, connectionRetryCount: Number(10), // TODO: get from settings enableKeepAliveUsingOptionsForUnstableNetworks: true, // TODO: get from settings + iceGatheringTimeout, }; const voipClient = await VoipClient.create(config); diff --git a/packages/ui-voip/src/lib/VoipClient.ts b/packages/ui-voip/src/lib/VoipClient.ts index 12af06ad3bf6f..7ab1fe3906eea 100644 --- a/packages/ui-voip/src/lib/VoipClient.ts +++ b/packages/ui-voip/src/lib/VoipClient.ts @@ -55,7 +55,7 @@ class VoipClient extends Emitter { } public async init() { - const { authPassword, authUserName, sipRegistrarHostnameOrIP, iceServers, webSocketURI } = this.config; + const { authPassword, authUserName, sipRegistrarHostnameOrIP, iceServers, webSocketURI, iceGatheringTimeout } = this.config; const transportOptions = { server: webSocketURI, @@ -64,7 +64,7 @@ class VoipClient extends Emitter { }; const sdpFactoryOptions = { - iceGatheringTimeout: 10, + ...(typeof iceGatheringTimeout === 'number' && { iceGatheringTimeout }), peerConnectionConfiguration: { iceServers }, };