diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 552191d1316..a4c7293f099 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -13,6 +13,17 @@ + + + + + + + + + + + @@ -87,6 +98,19 @@ + + + + + + + + diff --git a/app/definitions/Voip.ts b/app/definitions/Voip.ts new file mode 100644 index 00000000000..1f13d16e56f --- /dev/null +++ b/app/definitions/Voip.ts @@ -0,0 +1,5 @@ +export type IceServer = { + urls: string; + username?: string; + credential?: string; +}; diff --git a/app/lib/constants/defaultSettings.ts b/app/lib/constants/defaultSettings.ts index 74b3f1ed355..d2ea6708a49 100644 --- a/app/lib/constants/defaultSettings.ts +++ b/app/lib/constants/defaultSettings.ts @@ -300,5 +300,11 @@ export const defaultSettings = { Cloud_Workspace_AirGapped_Restrictions_Remaining_Days: { type: 'valueAsNumber' }, + VoIP_TeamCollab_Ice_Servers: { + type: 'valueAsString' + }, + VoIP_TeamCollab_Ice_Gathering_Timeout: { + type: 'valueAsNumber' + }, ...deprecatedSettings } as const; diff --git a/app/lib/services/voip/MediaCallLogger.ts b/app/lib/services/voip/MediaCallLogger.ts new file mode 100644 index 00000000000..0d9444d7f7a --- /dev/null +++ b/app/lib/services/voip/MediaCallLogger.ts @@ -0,0 +1,21 @@ +import type { IMediaSignalLogger } from '@rocket.chat/media-signaling'; + +export class MediaCallLogger implements IMediaSignalLogger { + log(...args: unknown[]): void { + console.log(`[Media Call] ${JSON.stringify(args)}`); + } + + debug(...args: unknown[]): void { + if (__DEV__) { + console.log(`[Media Call Debug] ${JSON.stringify(args)}`); + } + } + + error(...args: unknown[]): void { + console.log(`[Media Call Error] ${JSON.stringify(args)}`); + } + + warn(...args: unknown[]): void { + console.log(`[Media Call Warning] ${JSON.stringify(args)}`); + } +} diff --git a/app/lib/services/voip/MediaSessionInstance.ts b/app/lib/services/voip/MediaSessionInstance.ts new file mode 100644 index 00000000000..555093164ac --- /dev/null +++ b/app/lib/services/voip/MediaSessionInstance.ts @@ -0,0 +1,159 @@ +import { + ClientMediaSignal, + IClientMediaCall, + MediaCallWebRTCProcessor, + MediaSignalingSession, + WebRTCProcessorConfig +} from '@rocket.chat/media-signaling'; +import RNCallKeep from 'react-native-callkeep'; +import { registerGlobals } from 'react-native-webrtc'; + +import { mediaSessionStore } from './MediaSessionStore'; +import { store } from '../../store/auxStore'; +import sdk from '../sdk'; +import { parseStringToIceServers } from './parseStringToIceServers'; +import { IceServer } from '../../../definitions/Voip'; +import { IDDPMessage } from '../../../definitions/IDDPMessage'; + +class MediaSessionInstance { + private iceServers: IceServer[] = []; + private iceGatheringTimeout: number = 5000; + private mediaSignalListener: { stop: () => void } | null = null; + private mediaSignalsListener: { stop: () => void } | null = null; + private instance: MediaSignalingSession | null = null; + private storeTimeoutUnsubscribe: (() => void) | null = null; + private storeIceServersUnsubscribe: (() => void) | null = null; + + public init(userId: string): void { + this.stop(); + registerGlobals(); + this.configureRNCallKeep(); + this.configureIceServers(); + + mediaSessionStore.setWebRTCProcessorFactory( + (config: WebRTCProcessorConfig) => + new MediaCallWebRTCProcessor({ + ...config, + rtc: { ...config.rtc, iceServers: this.iceServers }, + iceGatheringTimeout: this.iceGatheringTimeout + }) + ); + mediaSessionStore.setSendSignalFn((signal: ClientMediaSignal) => { + sdk.methodCall('stream-notify-user', `${userId}/media-calls`, JSON.stringify(signal)); + }); + this.instance = mediaSessionStore.getInstance(userId); + mediaSessionStore.onChange(() => (this.instance = mediaSessionStore.getInstance(userId))); + + this.mediaSignalListener = sdk.onStreamData('stream-notify-user', (ddpMessage: IDDPMessage) => { + if (!this.instance) { + return; + } + const [, ev] = ddpMessage.fields.eventName.split('/'); + if (ev !== 'media-signal') { + return; + } + const signal = ddpMessage.fields.args[0]; + this.instance.processSignal(signal); + }); + + this.instance?.on('newCall', ({ call }: { call: IClientMediaCall }) => { + if (call && !call.hidden) { + call.emitter.on('stateChange', oldState => { + console.log(`📊 ${oldState} → ${call.state}`); + }); + + const displayName = call.contact.displayName || call.contact.username || 'Unknown'; + RNCallKeep.displayIncomingCall(call.callId, displayName, displayName, 'generic', false); + + call.emitter.on('ended', () => RNCallKeep.endCall(call.callId)); + } + }); + } + + private configureRNCallKeep() { + RNCallKeep.addEventListener('answerCall', async ({ callUUID }) => { + const mainCall = this.instance?.getMainCall(); + if (mainCall && mainCall.callId === callUUID) { + await mainCall.accept(); + RNCallKeep.setCurrentCallActive(mainCall.callId); + } else { + RNCallKeep.endCall(callUUID); + } + }); + + RNCallKeep.addEventListener('endCall', ({ callUUID }) => { + const mainCall = this.instance?.getMainCall(); + if (mainCall && mainCall.callId === callUUID) { + if (mainCall.state === 'ringing') { + mainCall.reject(); + } else { + mainCall.hangup(); + } + } + }); + + RNCallKeep.addEventListener('didPerformSetMutedCallAction', ({ muted, callUUID }) => { + const mainCall = this.instance?.getMainCall(); + if (mainCall && mainCall.callId === callUUID) { + mainCall.setMuted(muted); + } + }); + + RNCallKeep.addEventListener('didPerformDTMFAction', ({ digits }) => { + const mainCall = this.instance?.getMainCall(); + if (mainCall) { + mainCall.sendDTMF(digits); + } + }); + } + + private getIceServers() { + const iceServers = store.getState().settings.VoIP_TeamCollab_Ice_Servers as any; + return parseStringToIceServers(iceServers); + } + + private configureIceServers() { + this.iceServers = this.getIceServers(); + this.iceGatheringTimeout = store.getState().settings.VoIP_TeamCollab_Ice_Gathering_Timeout as number; + + this.storeTimeoutUnsubscribe = store.subscribe(() => { + const currentTimeout = store.getState().settings.VoIP_TeamCollab_Ice_Gathering_Timeout as number; + if (currentTimeout !== this.iceGatheringTimeout) { + this.iceGatheringTimeout = currentTimeout; + this.instance?.setIceGatheringTimeout(this.iceGatheringTimeout); + } + }); + + this.storeIceServersUnsubscribe = store.subscribe(() => { + const currentIceServers = this.getIceServers(); + if (currentIceServers !== this.iceServers) { + this.iceServers = currentIceServers; + this.instance?.setIceServers(this.iceServers); + } + }); + } + + private stop() { + if (this.mediaSignalListener) { + this.mediaSignalListener.stop(); + } + if (this.mediaSignalsListener) { + this.mediaSignalsListener.stop(); + } + RNCallKeep.removeEventListener('answerCall'); + RNCallKeep.removeEventListener('endCall'); + RNCallKeep.removeEventListener('didPerformSetMutedCallAction'); + RNCallKeep.removeEventListener('didPerformDTMFAction'); + if (this.storeTimeoutUnsubscribe) { + this.storeTimeoutUnsubscribe(); + } + if (this.storeIceServersUnsubscribe) { + this.storeIceServersUnsubscribe(); + } + if (this.instance) { + this.instance.endSession(); + } + } +} + +export const mediaSessionInstance = new MediaSessionInstance(); diff --git a/app/lib/services/voip/MediaSessionStore.ts b/app/lib/services/voip/MediaSessionStore.ts new file mode 100644 index 00000000000..b359287c8cc --- /dev/null +++ b/app/lib/services/voip/MediaSessionStore.ts @@ -0,0 +1,100 @@ +import { Emitter } from '@rocket.chat/emitter'; +import { MediaSignalingSession, MediaCallWebRTCProcessor } from '@rocket.chat/media-signaling'; +import type { MediaSignalTransport, ClientMediaSignal, WebRTCProcessorConfig } from '@rocket.chat/media-signaling'; +import { mediaDevices } from 'react-native-webrtc'; +import BackgroundTimer from 'react-native-background-timer'; + +import { MediaCallLogger } from './MediaCallLogger'; + +type SignalTransport = MediaSignalTransport; + +const randomStringFactory = (): string => + Date.now().toString(36) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); + +class MediaSessionStore extends Emitter<{ change: void }> { + private sessionInstance: MediaSignalingSession | null = null; + private sendSignalFn: SignalTransport | null = null; + private _webrtcProcessorFactory: ((config: WebRTCProcessorConfig) => MediaCallWebRTCProcessor) | null = null; + + private change() { + this.emit('change'); + } + + public onChange(callback: () => void) { + return this.on('change', callback); + } + + private webrtcProcessorFactory(config: WebRTCProcessorConfig): MediaCallWebRTCProcessor { + if (!this._webrtcProcessorFactory) { + throw new Error('WebRTC processor factory not set'); + } + return this._webrtcProcessorFactory(config); + } + + private sendSignal(signal: ClientMediaSignal) { + if (!this.sendSignalFn) { + throw new Error('Send signal function not set'); + } + return this.sendSignalFn(signal); + } + + private makeInstance(userId: string): MediaSignalingSession | null { + if (this.sessionInstance !== null) { + this.sessionInstance.endSession(); + this.sessionInstance = null; + } + + if (!this._webrtcProcessorFactory || !this.sendSignalFn) { + throw new Error('WebRTC processor factory and send signal function must be set'); + } + + this.sessionInstance = new MediaSignalingSession({ + userId, + transport: (signal: ClientMediaSignal) => this.sendSignal(signal), + processorFactories: { + webrtc: (config: WebRTCProcessorConfig) => this.webrtcProcessorFactory(config) + }, + mediaStreamFactory: (constraints: any) => mediaDevices.getUserMedia(constraints) as unknown as Promise, + randomStringFactory, + logger: new MediaCallLogger(), + timerProcessor: { + setInterval: (callback: () => void, interval: number) => BackgroundTimer.setInterval(callback, interval), + clearInterval: (interval: number) => BackgroundTimer.clearInterval(interval), + setTimeout: (callback: () => void, timeout: number) => BackgroundTimer.setTimeout(callback, timeout), + clearTimeout: (timeout: number) => BackgroundTimer.clearTimeout(timeout) + } + }); + + this.change(); + return this.sessionInstance; + } + + public getInstance(userId?: string): MediaSignalingSession | null { + if (!userId) { + throw new Error('User Id is required'); + } + + if (this.sessionInstance?.userId === userId) { + return this.sessionInstance; + } + + return this.makeInstance(userId); + } + + public setSendSignalFn(sendSignalFn: SignalTransport) { + this.sendSignalFn = sendSignalFn; + this.change(); + } + + public setWebRTCProcessorFactory(factory: (config: WebRTCProcessorConfig) => MediaCallWebRTCProcessor): void { + this._webrtcProcessorFactory = factory; + this.change(); + } + + public getCurrentInstance(): MediaSignalingSession | null { + return this.sessionInstance; + } +} + +// TODO: change name +export const mediaSessionStore = new MediaSessionStore(); diff --git a/app/lib/services/voip/parseStringToIceServers.ts b/app/lib/services/voip/parseStringToIceServers.ts new file mode 100644 index 00000000000..0a339d4a84d --- /dev/null +++ b/app/lib/services/voip/parseStringToIceServers.ts @@ -0,0 +1,24 @@ +import type { IceServer } from '../../../definitions/Voip'; + +export const parseStringToIceServer = (server: string): IceServer => { + const credentials = server.trim().split('@'); + const urls = credentials.pop() as string; + const [username, credential] = credentials.length === 1 ? credentials[0].split(':') : []; + + return { + urls, + ...(username && + credential && { + username: decodeURIComponent(username), + credential: decodeURIComponent(credential) + }) + }; +}; + +export const parseStringToIceServers = (string: string): IceServer[] => { + if (!string) { + return []; + } + const lines = string.trim() ? string.split(',') : []; + return lines.map(line => parseStringToIceServer(line)); +}; diff --git a/app/lib/store/index.ts b/app/lib/store/index.ts index 3ae917484ac..25011f0f648 100644 --- a/app/lib/store/index.ts +++ b/app/lib/store/index.ts @@ -18,8 +18,8 @@ if (__DEV__) { applyAppStateMiddleware(), applyInternetStateMiddleware(), applyMiddleware(reduxImmutableStateInvariant), - applyMiddleware(sagaMiddleware), - applyMiddleware(logger) + applyMiddleware(sagaMiddleware) + // applyMiddleware(logger) ); } else { sagaMiddleware = createSagaMiddleware(); diff --git a/app/sagas/login.js b/app/sagas/login.js index 91dfe225f0c..b134e524013 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -3,6 +3,9 @@ import { call, cancel, delay, fork, put, race, select, take, takeLatest } from ' import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import { Q } from '@nozbe/watermelondb'; import * as Keychain from 'react-native-keychain'; +import RNCallKeep from 'react-native-callkeep'; +import { PermissionsAndroid } from 'react-native'; +import BackgroundTimer from 'react-native-background-timer'; import moment from 'moment'; import * as types from '../actions/actionsTypes'; @@ -42,6 +45,7 @@ import appNavigation from '../lib/navigation/appNavigation'; import { showActionSheetRef } from '../containers/ActionSheet'; import { SupportedVersionsWarning } from '../containers/SupportedVersions'; import { isIOS } from '../lib/methods/helpers'; +import { mediaSessionInstance } from '../lib/services/voip/MediaSessionInstance'; const getServer = state => state.server.server; const loginWithPasswordCall = args => loginWithPassword(args); @@ -214,6 +218,55 @@ const fetchUsersRoles = function* fetchRoomsFork() { } }; +function* initCallKeep() { + try { + const options = { + ios: { + appName: 'Rocket.Chat', + includesCallsInRecents: false + }, + android: { + alertTitle: 'Permissions required', + alertDescription: 'This application needs to access your phone accounts', + cancelButton: 'Cancel', + okButton: 'Ok', + imageName: 'phone_account_icon', + additionalPermissions: [ + PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE, + PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, + PermissionsAndroid.PERMISSIONS.CALL_PHONE + ], + // Required to get audio in background when using Android 11 + foregroundService: { + channelId: 'chat.rocket.reactnative', + channelName: 'Rocket.Chat', + notificationTitle: 'Voice call is running on background' + } + } + }; + + RNCallKeep.setup(options); + RNCallKeep.canMakeMultipleCalls(false); + + const start = Date.now(); + setInterval(() => { + console.log('Timer fired after', Date.now() - start, 'ms'); + }, 1000); + } catch (e) { + log(e); + } +} + +const startVoipFork = function* startVoipFork() { + try { + yield call(initCallKeep); + const userId = yield select(state => state.login.user.id); + mediaSessionInstance.init(userId); + } catch (e) { + log(e); + } +}; + const handleLoginSuccess = function* handleLoginSuccess({ user }) { try { getUserPresence(user.id); @@ -230,6 +283,8 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) { yield fork(fetchEnterpriseModulesFork, { user }); yield fork(subscribeSettingsFork); yield fork(fetchUsersRoles); + yield delay(1000); + yield fork(startVoipFork); setLanguage(user?.language); diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0adfeaba160..0c0ce8538b8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -209,6 +209,7 @@ PODS: - hermes-engine (0.79.4): - hermes-engine/Pre-built (= 0.79.4) - hermes-engine/Pre-built (0.79.4) + - JitsiWebRTC (124.0.2) - libavif/core (0.11.1) - libavif/libdav1d (0.11.1): - libavif/core @@ -1816,6 +1817,9 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga + - react-native-webrtc (124.0.7): + - JitsiWebRTC (~> 124.0.0) + - React-Core - react-native-webview (13.15.0): - DoubleConversion - glog @@ -2712,6 +2716,7 @@ DEPENDENCIES: - react-native-restart (from `../node_modules/react-native-restart`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - "react-native-slider (from `../node_modules/@react-native-community/slider`)" + - react-native-webrtc (from `../node_modules/react-native-webrtc`) - react-native-webview (from `../node_modules/react-native-webview`) - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`) @@ -2783,6 +2788,7 @@ SPEC REPOS: - GoogleAppMeasurement - GoogleDataTransport - GoogleUtilities + - JitsiWebRTC - libavif - libdav1d - libwebp @@ -2939,6 +2945,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-safe-area-context" react-native-slider: :path: "../node_modules/@react-native-community/slider" + react-native-webrtc: + :path: "../node_modules/react-native-webrtc" react-native-webview: :path: "../node_modules/react-native-webview" React-NativeModulesApple: @@ -3091,6 +3099,7 @@ SPEC CHECKSUMS: GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d hermes-engine: 8b5a5eb386b990287d072fd7b6f6ebd9544dd251 + JitsiWebRTC: b47805ab5668be38e7ee60e2258f49badfe8e1d0 libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7 libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 @@ -3142,6 +3151,7 @@ SPEC CHECKSUMS: react-native-restart: f6f591aeb40194c41b9b5013901f00e6cf7d0f29 react-native-safe-area-context: 5928d84c879db2f9eb6969ca70e68f58623dbf25 react-native-slider: 605e731593322c4bb2eb48d7d64e2e4dbf7cbd77 + react-native-webrtc: e8f0ce746353adc2744a2b933645e1aeb41eaa74 react-native-webview: e28f476ea60826ef0b1d7297244db1dfbec74acd React-NativeModulesApple: 5b234860053d0dd11f3442f38b99688ff1c9733b React-oscompat: 472a446c740e39ee39cd57cd7bfd32177c763a2b @@ -3172,7 +3182,7 @@ SPEC CHECKSUMS: React-timing: 2d07431f1c1203c5b0aaa6dc7b5f503704519218 React-utils: 67cf7dcfc18aa4c56bec19e11886033bb057d9fa ReactAppDependencyProvider: bf62814e0fde923f73fc64b7e82d76c63c284da9 - ReactCodegen: c51a63d05629675dd61caf58d1a093c4457972c0 + ReactCodegen: df3ff45729335a27d1c85bed1787e79783289968 ReactCommon: 177fca841e97b2c0e288e86097b8be04c6e7ae36 RNBootSplash: 1280eeb18d887de0a45bb4923d4fc56f25c8b99c RNCAsyncStorage: edb872909c88d8541c0bfade3f86cd7784a7c6b3 diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 7f65bcc902d..0385f066b0b 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -1658,10 +1658,12 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-defaults-RocketChatRN/Pods-defaults-RocketChatRN-frameworks.sh", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/JitsiWebRTC/WebRTC.framework/WebRTC", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebRTC.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; @@ -2145,10 +2147,12 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-defaults-Rocket.Chat/Pods-defaults-Rocket.Chat-frameworks.sh", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/JitsiWebRTC/WebRTC.framework/WebRTC", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebRTC.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; diff --git a/package.json b/package.json index f6a01974cf0..ffceda280af 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@react-navigation/elements": "^2.6.1", "@react-navigation/native": "^7.1.16", "@react-navigation/native-stack": "^7.3.23", + "@rocket.chat/media-signaling": "/Users/diegomello/Development/Work/Rocket.Chat/packages/media-signaling", "@rocket.chat/message-parser": "^0.31.31", "@rocket.chat/mobile-crypto": "RocketChat/rocket.chat-mobile-crypto", "@rocket.chat/sdk": "RocketChat/Rocket.Chat.js.SDK#mobile", @@ -98,6 +99,7 @@ "react-native-animatable": "1.3.3", "react-native-background-timer": "2.4.1", "react-native-bootsplash": "^6.3.8", + "react-native-callkeep": "^4.3.16", "react-native-config-reader": "4.1.1", "react-native-console-time-polyfill": "1.2.3", "react-native-device-info": "11.1.0", @@ -130,6 +132,7 @@ "react-native-svg": "^15.12.1", "react-native-url-polyfill": "2.0.0", "react-native-vector-icons": "9.2.0", + "react-native-webrtc": "^124.0.7", "react-native-webview": "^13.15.0", "react-redux": "8.0.5", "reanimated-tab-view": "^0.3.0", diff --git a/patches/@rocket.chat+sdk+1.3.3-mobile.patch b/patches/@rocket.chat+sdk+1.3.3-mobile.patch new file mode 100644 index 00000000000..ab0a55a87d2 --- /dev/null +++ b/patches/@rocket.chat+sdk+1.3.3-mobile.patch @@ -0,0 +1,15 @@ +diff --git a/node_modules/@rocket.chat/sdk/lib/drivers/ddp.ts b/node_modules/@rocket.chat/sdk/lib/drivers/ddp.ts +index 19d31ae..d5295b5 100644 +--- a/node_modules/@rocket.chat/sdk/lib/drivers/ddp.ts ++++ b/node_modules/@rocket.chat/sdk/lib/drivers/ddp.ts +@@ -549,7 +549,9 @@ export class DDPDriver extends EventEmitter implements ISocket, IDriver { + 'uiInteraction', + 'e2ekeyRequest', + 'userData', +- 'video-conference' ++ 'video-conference', ++ 'media-signal', ++ 'media-calls' + ].map(event => this.subscribe(topic, `${this.userId}/${event}`, false))) + } + diff --git a/yarn.lock b/yarn.lock index b7f53c6362e..35e5f5764b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4923,6 +4923,11 @@ resolved "https://registry.yarnpkg.com/@redux-saga/types/-/types-1.2.1.tgz#9403f51c17cae37edf870c6bc0c81c1ece5ccef8" integrity sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA== +"@rocket.chat/emitter@~0.31.25": + version "0.31.25" + resolved "https://registry.yarnpkg.com/@rocket.chat/emitter/-/emitter-0.31.25.tgz#17dd7838dc988ebc5fcd96343c4431d5cef45845" + integrity sha512-hw5BpDlNwpYSb+K5X3DNMNUVEVXxmXugUPetGZGCWvntSVFsOjYuVEypoKW6vBBXSfqCBb0kN1npYcKEb4NFBw== + "@rocket.chat/eslint-config@^0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@rocket.chat/eslint-config/-/eslint-config-0.4.0.tgz#d648decd02ae739eac17a32e1630332a75318ea1" @@ -4930,6 +4935,12 @@ dependencies: eslint-plugin-import "^2.17.2" +"@rocket.chat/media-signaling@file:../Rocket.Chat/packages/media-signaling": + version "0.0.1" + dependencies: + "@rocket.chat/emitter" "~0.31.25" + ajv "^8.17.1" + "@rocket.chat/message-parser@^0.31.31": version "0.31.31" resolved "https://registry.yarnpkg.com/@rocket.chat/message-parser/-/message-parser-0.31.31.tgz#9a3eea7602ac37387c6384577623865c8d536003" @@ -5932,6 +5943,16 @@ ajv@^8.0.0, ajv@^8.6.3, ajv@^8.9.0: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@^8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + anser@^1.4.9: version "1.4.10" resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.10.tgz#befa3eddf282684bd03b63dcda3927aef8c2e35b" @@ -6491,7 +6512,7 @@ bare-path@^2.0.0, bare-path@^2.1.0: dependencies: bare-os "^2.1.0" -base64-js@^1.2.3, base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@1.5.1, base64-js@^1.2.3, base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -7407,6 +7428,13 @@ debug@4, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" +debug@4.3.4, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -7421,13 +7449,6 @@ debug@^4.3.1: dependencies: ms "2.1.2" -debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - debug@^4.3.5, debug@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" @@ -8485,6 +8506,11 @@ event-pubsub@4.3.0: resolved "https://registry.yarnpkg.com/event-pubsub/-/event-pubsub-4.3.0.tgz#f68d816bc29f1ec02c539dc58c8dd40ce72cb36e" integrity sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ== +event-target-shim@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-6.0.2.tgz#ea5348c3618ee8b62ff1d344f01908ee2b8a2b71" + integrity sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA== + event-target-shim@^5.0.0, event-target-shim@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" @@ -8744,6 +8770,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.0.tgz#66eecff6c764c0df9b762e62ca7edcfb53b4edfa" + integrity sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA== + fast-xml-parser@^4.0.12, fast-xml-parser@^4.2.4: version "4.4.1" resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz#86dbf3f18edf8739326447bcaac31b4ae7f6514f" @@ -12886,6 +12917,11 @@ react-native-bootsplash@^6.3.8: ts-dedent "^2.2.0" xml-formatter "^3.6.5" +react-native-callkeep@^4.3.16: + version "4.3.16" + resolved "https://registry.yarnpkg.com/react-native-callkeep/-/react-native-callkeep-4.3.16.tgz#56291796984b896113ef00f8b67ae3fe177baf70" + integrity sha512-aIxn02T5zW4jNPyzRdFGTWv6xD3Vy/1AkBMB6iYvWZEHWnfmgNGF0hELqg03Vbc2BNUhfqpu17aIydos+5Hurg== + react-native-config-reader@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/react-native-config-reader/-/react-native-config-reader-4.1.1.tgz#478b69e32adcc2e9a14f6ef5fa2cbbe012b9a27e" @@ -13130,6 +13166,15 @@ react-native-vector-icons@9.2.0: prop-types "^15.7.2" yargs "^16.1.1" +react-native-webrtc@^124.0.7: + version "124.0.7" + resolved "https://registry.yarnpkg.com/react-native-webrtc/-/react-native-webrtc-124.0.7.tgz#f50647a8eb3fae0ef29843eb1b5fe2c4ff75a56e" + integrity sha512-gnXPdbUS8IkKHq9WNaWptW/yy5s6nMyI6cNn90LXdobPVCgYSk6NA2uUGdT4c4J14BRgaFA95F+cR28tUPkMVA== + dependencies: + base64-js "1.5.1" + debug "4.3.4" + event-target-shim "6.0.2" + react-native-webview@^13.15.0: version "13.15.0" resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-13.15.0.tgz#b6d2f8d8dd65897db76659ddd8198d2c74ec5a79"