diff --git a/app/products/calls/connection/connection.ts b/app/products/calls/connection/connection.ts index 2586e29cc..ff1fb243a 100644 --- a/app/products/calls/connection/connection.ts +++ b/app/products/calls/connection/connection.ts @@ -5,7 +5,7 @@ import {RTCMonitor, RTCPeer} from '@mattermost/calls/lib'; import {deflate} from 'pako'; import {DeviceEventEmitter, type EmitterSubscription, NativeEventEmitter, NativeModules, Platform} from 'react-native'; import InCallManager from 'react-native-incall-manager'; -import {mediaDevices, MediaStream, MediaStreamTrack, RTCPeerConnection} from 'react-native-webrtc'; +import {mediaDevices, MediaStream, MediaStreamTrack, registerGlobals} from 'react-native-webrtc'; import {setPreferredAudioRoute, setSpeakerphoneOn} from '@calls/actions/calls'; import { @@ -19,7 +19,7 @@ import {getICEServersConfigs} from '@calls/utils'; import {WebsocketEvents} from '@constants'; import {getServerCredentials} from '@init/credentials'; import NetworkManager from '@managers/network_manager'; -import {getFullErrorMessage} from '@utils/errors'; +import {getErrorMessage, getFullErrorMessage} from '@utils/errors'; import {logDebug, logError, logInfo, logWarning} from '@utils/log'; import {WebSocketClient, wsReconnectionTimeoutErr} from './websocket_client'; @@ -80,10 +80,29 @@ export async function newConnection( } }; + // Registering WebRTC globals (e.g. RTCPeerConnection) + registerGlobals(); + // getClient can throw an error, which will be handled by the caller. const client = NetworkManager.getClient(serverUrl); const credentials = await getServerCredentials(serverUrl); + let config; + try { + config = await client.getCallsConfig(); + } catch (err) { + throw new Error(`calls: fetching calls config: ${getFullErrorMessage(err)}`); + } + + let av1Support = false; + if (config.EnableAV1 && !config.EnableSimulcast) { + try { + av1Support = Boolean(await RTCPeer.getVideoCodec('video/AV1')); + } catch (err) { + throw new Error(`calls: failed to check AV1 support: ${getErrorMessage(err)}`); + } + } + const ws = new WebSocketClient(serverUrl, client.getWebSocketUrl(), credentials?.token); // Throws an error, to be caught by caller. @@ -228,23 +247,18 @@ export async function newConnection( }); } else { logDebug('calls: ws open, sending join msg'); + ws.send('join', { channelID, title, threadID: rootId, + av1Support, }); } }); ws.on('join', async () => { logDebug('calls: join ack received, initializing connection'); - let config; - try { - config = await client.getCallsConfig(); - } catch (err) { - logError('calls: fetching calls config:', getFullErrorMessage(err)); - return; - } const iceConfigs = getICEServersConfigs(config); if (config.NeedsTURNCredentials) { @@ -313,10 +327,6 @@ export async function newConnection( peer = new RTCPeer({ iceServers: iceConfigs || [], logger, - webrtc: { - MediaStream, - RTCPeerConnection, - }, }); rtcMonitor = new RTCMonitor({ diff --git a/app/products/calls/types/calls.ts b/app/products/calls/types/calls.ts index 1d4dad9cf..dc2da1f89 100644 --- a/app/products/calls/types/calls.ts +++ b/app/products/calls/types/calls.ts @@ -1,12 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import type { - CallJobState, - CallsConfig, - EmojiData, - UserReactionData, +import { + TranscribeAPI, + type CallJobState, + type CallsConfig, + type EmojiData, + type UserReactionData, } from '@mattermost/calls/lib/types'; + import type UserModel from '@typings/database/models/servers/user'; export type GlobalCallsState = { @@ -173,6 +175,8 @@ export const DefaultCallsConfig: CallsConfigState = { EnableTranscriptions: false, EnableLiveCaptions: false, HostControlsAllowed: false, + EnableAV1: false, + TranscribeAPI: TranscribeAPI.WhisperCPP, }; export type ApiResp = { diff --git a/package-lock.json b/package-lock.json index 6a4c696d6..736fcf69c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "mattermost-mobile", - "version": "2.18.0", + "version": "2.19.0", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { @@ -17,7 +17,7 @@ "@formatjs/intl-numberformat": "8.10.3", "@formatjs/intl-pluralrules": "5.2.14", "@gorhom/bottom-sheet": "4.6.3", - "@mattermost/calls": "github:mattermost/calls-common#cc5e65f6c103138fd013d6fa45eb33bfe7544f2a", + "@mattermost/calls": "github:mattermost/calls-common#09f1d4e715ccaf4f161e5e5340e251997336ee3d", "@mattermost/compass-icons": "0.1.45", "@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard", "@mattermost/keyboard-tracker": "file:./libraries/@mattermost/keyboard-tracker", @@ -5562,10 +5562,10 @@ } }, "node_modules/@mattermost/calls": { - "name": "@calls/common", - "version": "0.14.0", - "resolved": "git+ssh://git@github.com/mattermost/calls-common.git#cc5e65f6c103138fd013d6fa45eb33bfe7544f2a", - "integrity": "sha512-fWCVnjuU3LQ8RO35uI9Qypi7HSVWoALcbNIotNcWd52XQ+BLgt69nSpKRli9qbvj4d9W/UgPaT3bOsyBvIXQrA==" + "name": "@mattermost/calls-common", + "version": "0.27.2", + "resolved": "git+ssh://git@github.com/mattermost/calls-common.git#09f1d4e715ccaf4f161e5e5340e251997336ee3d", + "integrity": "sha512-8nBf2upZbCa0GTkusCmmHlT8Tz4BmegAFoDNK82Y3o+wfZd3ZESIG6GEG6aKlrXt/fwU7iCaSQw59WxDXhun9w==" }, "node_modules/@mattermost/commonmark": { "version": "0.30.1-2", diff --git a/package.json b/package.json index 0f7def730..31c046a9d 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.3", - "@mattermost/calls": "github:mattermost/calls-common#cc5e65f6c103138fd013d6fa45eb33bfe7544f2a", + "@mattermost/calls": "github:mattermost/calls-common#09f1d4e715ccaf4f161e5e5340e251997336ee3d", "@mattermost/compass-icons": "0.1.45", "@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard", "@mattermost/keyboard-tracker": "file:./libraries/@mattermost/keyboard-tracker",