From e693431dec9cbc1cf2b253e5a38c1e115e69d071 Mon Sep 17 00:00:00 2001 From: Claudio Costa Date: Wed, 9 Oct 2024 16:33:33 -0600 Subject: [PATCH] [MM-45894] Calls: support for signaling media tracks using data channels (#8246) * Replace pako with fflate * Allow signaling through data channel * Update calls-common --- app/products/calls/connection/connection.ts | 29 +++++++++----------- app/products/calls/types/calls.ts | 1 + package-lock.json | 30 ++++++++++++++------- package.json | 4 +-- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/app/products/calls/connection/connection.ts b/app/products/calls/connection/connection.ts index 677834759c..0f442deaa7 100644 --- a/app/products/calls/connection/connection.ts +++ b/app/products/calls/connection/connection.ts @@ -2,10 +2,10 @@ // See LICENSE.txt for license information. import {RTCMonitor, RTCPeer, parseRTCStats} from '@mattermost/calls/lib'; -import {deflate} from 'pako'; +import {zlibSync, strToU8} from 'fflate'; import {DeviceEventEmitter, type EmitterSubscription, NativeEventEmitter, NativeModules, Platform} from 'react-native'; import InCallManager from 'react-native-incall-manager'; -import {mediaDevices, MediaStream, MediaStreamTrack, registerGlobals} from 'react-native-webrtc'; +import {mediaDevices, MediaStream, MediaStreamTrack, registerGlobals, RTCSessionDescription} from 'react-native-webrtc'; import {setPreferredAudioRoute, setSpeakerphoneOn} from '@calls/actions/calls'; import { @@ -311,6 +311,7 @@ export async function newConnection( title, threadID: rootId, av1Support, + dcSignaling: config.EnableDCSignaling, }); } }); @@ -385,6 +386,7 @@ export async function newConnection( peer = new RTCPeer({ iceServers: iceConfigs || [], logger, + dcSignaling: config.EnableDCSignaling, }); collectICEStats(); @@ -396,22 +398,20 @@ export async function newConnection( }); rtcMonitor.on('mos', processMeanOpinionScore); - peer.on('offer', (sdp) => { - logDebug(`calls: local offer, sending: ${JSON.stringify(sdp)}`); - ws.send('sdp', { - data: deflate(JSON.stringify(sdp)), - }, true); - }); + const sdpHandler = (sdp: RTCSessionDescription) => { + const payload = JSON.stringify(sdp); - peer.on('answer', (sdp) => { - logDebug(`calls: local answer, sending: ${JSON.stringify(sdp)}`); + // SDP data is compressed using zlib since it's text based + // and can grow substantially, potentially hitting the maximum + // message size (8KB). ws.send('sdp', { - data: deflate(JSON.stringify(sdp)), + data: zlibSync(strToU8(payload)), }, true); - }); + }; + peer.on('offer', sdpHandler); + peer.on('answer', sdpHandler); peer.on('candidate', (candidate) => { - logDebug(`calls: local candidate: ${JSON.stringify(candidate)}`); ws.send('ice', { data: JSON.stringify(candidate), }); @@ -449,9 +449,6 @@ export async function newConnection( if (!msg) { return; } - if (msg.type !== 'ping') { - logDebug('calls: remote signal', data); - } if (msg.type === 'answer' || msg.type === 'candidate' || msg.type === 'offer') { peer?.signal(data); } diff --git a/app/products/calls/types/calls.ts b/app/products/calls/types/calls.ts index b8803bafbb..9577789dc0 100644 --- a/app/products/calls/types/calls.ts +++ b/app/products/calls/types/calls.ts @@ -179,6 +179,7 @@ export const DefaultCallsConfig: CallsConfigState = { EnableAV1: false, TranscribeAPI: TranscribeAPI.WhisperCPP, GroupCallsAllowed: true, // Set to true to keep backward compatibility with older servers. + EnableDCSignaling: false, }; export type ApiResp = { diff --git a/package-lock.json b/package-lock.json index ebc4241779..c1be105a89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@formatjs/intl-numberformat": "8.10.3", "@formatjs/intl-pluralrules": "5.2.14", "@gorhom/bottom-sheet": "4.6.4", - "@mattermost/calls": "github:mattermost/calls-common#1ce6defb1ee0c1e0f106ddff8f46c37d10d60b76", + "@mattermost/calls": "github:mattermost/calls-common#8d2b13bd2f10847a4be461dd4225fef2ade06ab9", "@mattermost/compass-icons": "0.1.45", "@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard", "@mattermost/keyboard-tracker": "file:./libraries/@mattermost/keyboard-tracker", @@ -56,12 +56,12 @@ "expo-store-review": "7.0.2", "expo-video-thumbnails": "8.0.0", "expo-web-browser": "13.0.3", + "fflate": "0.8.2", "fuse.js": "7.0.0", "html-entities": "2.5.2", "mime-db": "1.53.0", "moment-timezone": "0.5.45", "node-html-parser": "6.1.13", - "pako": "2.1.0", "path-to-regexp": "8.1.0", "react": "18.2.0", "react-freeze": "1.0.4", @@ -5850,8 +5850,20 @@ "node_modules/@mattermost/calls": { "name": "@mattermost/calls-common", "version": "0.27.2", - "resolved": "git+ssh://git@github.com/mattermost/calls-common.git#1ce6defb1ee0c1e0f106ddff8f46c37d10d60b76", - "integrity": "sha512-VeX0GT1g8bl7AqG5TJEnbkTTVbc+CqZttpPBKYDkMJd86CGjtURc4o83OUu3TNsEI3opSpJfbetScUTG9TWNLw==" + "resolved": "git+ssh://git@github.com/mattermost/calls-common.git#8d2b13bd2f10847a4be461dd4225fef2ade06ab9", + "integrity": "sha512-jze9YO7n9c8AgaE2FOMzj8g2ieqczNfCzah7W6TeQtC0Ufhe3jcGG99DNtrB3tHeiBsp/ZlrvBXCVpA/oQR6YA==", + "dependencies": { + "@msgpack/msgpack": "^3.0.0-beta2", + "fflate": "^0.8.2" + } + }, + "node_modules/@mattermost/calls/node_modules/@msgpack/msgpack": { + "version": "3.0.0-beta2", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.0.0-beta2.tgz", + "integrity": "sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==", + "engines": { + "node": ">= 14" + } }, "node_modules/@mattermost/commonmark": { "version": "0.30.1-2", @@ -14790,6 +14802,11 @@ "integrity": "sha512-e6eB7zN6UBSwGVwrbWVH+gdLnkW9WwHhmq2YDK1Sh30pzx1onRVGBvogTlUeWxwTa+L86NYdo4hFkh7O8ZjSnA==", "license": "MIT" }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -21542,11 +21559,6 @@ "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", "license": "BlueOak-1.0.0" }, - "node_modules/pako": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", diff --git a/package.json b/package.json index 5a08a48517..600f75bfa4 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@formatjs/intl-numberformat": "8.10.3", "@formatjs/intl-pluralrules": "5.2.14", "@gorhom/bottom-sheet": "4.6.4", - "@mattermost/calls": "github:mattermost/calls-common#1ce6defb1ee0c1e0f106ddff8f46c37d10d60b76", + "@mattermost/calls": "github:mattermost/calls-common#8d2b13bd2f10847a4be461dd4225fef2ade06ab9", "@mattermost/compass-icons": "0.1.45", "@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard", "@mattermost/keyboard-tracker": "file:./libraries/@mattermost/keyboard-tracker", @@ -57,12 +57,12 @@ "expo-store-review": "7.0.2", "expo-video-thumbnails": "8.0.0", "expo-web-browser": "13.0.3", + "fflate": "0.8.2", "fuse.js": "7.0.0", "html-entities": "2.5.2", "mime-db": "1.53.0", "moment-timezone": "0.5.45", "node-html-parser": "6.1.13", - "pako": "2.1.0", "path-to-regexp": "8.1.0", "react": "18.2.0", "react-freeze": "1.0.4",