Compare commits

...

13 Commits

Author SHA1 Message Date
damencho
17e1774f6e Revert "drop: debug."
This reverts commit 7d48ea1bca.
2025-04-29 17:17:53 -05:00
damencho
249bd3a660 Revert "drop: fix build."
This reverts commit 23bba927f3.
2025-04-29 17:17:49 -05:00
damencho
23bba927f3 drop: fix build. 2025-04-29 16:30:31 -05:00
damencho
7d48ea1bca drop: debug. 2025-04-29 14:31:04 -05:00
damencho
a07a1cfe93 fix(prosody): Adds a nil check for ends_with utility. 2025-04-28 15:43:42 -05:00
damencho
16c45c15c8 fix(prosody): Fixes filter rayo message when int id is used.
Make sure we add string values to the stanza.
2025-04-28 13:50:10 -05:00
Jaya Allamsetty
5d5d6c3068 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1979.0.0+9da20d5f...v1980.0.0+34a32e86
2025-04-25 14:26:20 -04:00
Jaya Allamsetty
19399ec123 fix(test): Fix codec selection test 2025-04-24 11:05:53 -04:00
Calinteodor
3c27f15490 fix(invite/add-people-dialog): isCorsAvatarURL update (#15959)
For the case of AddPeopleDialog, isCORSAvatarURL takes url param as a function aka an Icon component, thus we need it to return false.
2025-04-24 09:41:47 +03:00
Saúl Ibarra Corretgé
607073c669 feat(local-recordings) remove recording time limit
Use the `showSaveFilePicker` File System Access API to pre-select the
file for download and stream the contents there. The browser uses a
temporary file as the buffer, thus not requiring us to buffer the
contents in memory.

Also change the container to MP4, since we have no way to fix the
seeking problem since we don't have the file in memory. Good news is
that it's supported since Chrome 126 and we can feature detect it!

Finally, add a helper `isSupprted` method which feature-detects
everything we need to make this work.

Ref: https://developer.mozilla.org/en-US/docs/Web/API/Window/showSaveFilePicker
Ref: https://groups.google.com/a/chromium.org/g/blink-dev/c/p1OMVj1FrMI/m/6FdLk7rZAQAJ
2025-04-23 13:52:02 -04:00
Hristo Terezov
f92ee57f9c chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1973.0.0+64dcc15c...v1979.0.0+9da20d5f
2025-04-23 12:29:31 -05:00
Hristo Terezov
32331d7465 doc(config): testing.enableAV1ForFF 2025-04-23 12:08:19 -05:00
Hristo Terezov
88685c43fb fix(codecSelection): test 2025-04-23 12:08:19 -05:00
11 changed files with 97 additions and 194 deletions

View File

@@ -89,6 +89,9 @@ var config = {
// Enables use of getDisplayMedia in electron
// electronUseGetDisplayMedia: false,
// Enables AV1 codec for FF. Note: By default it is disabled.
// enableAV1ForFF: false,
// Enables the use of the codec selection API supported by the browsers .
// enableCodecSelectionAPI: false,

121
package-lock.json generated
View File

@@ -61,7 +61,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1973.0.0+64dcc15c/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1980.0.0+34a32e86/lib-jitsi-meet.tgz",
"lodash-es": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -116,7 +116,6 @@
"util": "0.12.1",
"uuid": "8.3.2",
"wasm-check": "2.0.1",
"webm-duration-fix": "1.0.4",
"windows-iana": "3.1.0",
"zxcvbn": "4.4.2"
},
@@ -11926,11 +11925,6 @@
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"node_modules/ebml-block": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/ebml-block/-/ebml-block-1.1.2.tgz",
"integrity": "sha512-HgNlIsRFP6D9VKU5atCeHRJY7XkJP8bOe8yEhd8NB7B3b4++VWTyauz6g650iiPmLfPLGlVpoJmGSgMfXDYusg=="
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
@@ -15146,14 +15140,6 @@
"node": ">=18"
}
},
"node_modules/int64-buffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-1.0.1.tgz",
"integrity": "sha512-+3azY4pXrjAupJHU1V9uGERWlhoqNswJNji6aD/02xac7oxol508AsMC5lxKhEqyZeDFy3enq5OGWXF4u75hiw==",
"engines": {
"node": ">= 4.5.0"
}
},
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -16996,8 +16982,8 @@
},
"node_modules/lib-jitsi-meet": {
"version": "0.0.0",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1973.0.0+64dcc15c/lib-jitsi-meet.tgz",
"integrity": "sha512-uwFKP+eZpxA8AXpv/XWk4qbyHNEovPS517Kz8gOhQSzYZpCnaN4smc3kfawInWw5da+GXtljVkkWXCWn3Lergw==",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1980.0.0+34a32e86/lib-jitsi-meet.tgz",
"integrity": "sha512-NmjVrkhBgUhAHe84oEVGi5keXmO92RtVznchdPep6vJz9O2A6GPN9Ap+DZOoiK693bm9lRdzDIEIFn5GnlLfQg==",
"license": "Apache-2.0",
"dependencies": {
"@jitsi/js-utils": "2.2.1",
@@ -17006,13 +16992,13 @@
"@jitsi/rtcstats": "9.7.0",
"@testrtc/watchrtc-sdk": "1.38.2",
"async-es": "3.2.4",
"base64-js": "1.3.1",
"base64-js": "1.5.1",
"current-executing-script": "0.1.3",
"jquery": "3.6.1",
"lodash-es": "4.17.21",
"sdp-transform": "2.3.0",
"strophe.js": "https://github.com/jitsi/strophejs/releases/download/v1.5-jitsi-3/strophe.js-1.5.0.tgz",
"uuid": "8.1.0",
"uuid": "8.3.2",
"webrtc-adapter": "8.1.1"
}
},
@@ -17035,19 +17021,6 @@
"uuid": "dist/bin/uuid"
}
},
"node_modules/lib-jitsi-meet/node_modules/base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"node_modules/lib-jitsi-meet/node_modules/uuid": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
"integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
@@ -24797,40 +24770,6 @@
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
},
"node_modules/webm-duration-fix": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/webm-duration-fix/-/webm-duration-fix-1.0.4.tgz",
"integrity": "sha512-kvhmSmEnuohtK+j+mJswqCCM2ViKb9W8Ch0oAxcaeUvpok5CsMORQLnea+CYKDXPG6JH12H0CbRK85qhfeZLew==",
"dependencies": {
"buffer": "^6.0.3",
"ebml-block": "^1.1.2",
"events": "^3.3.0",
"int64-buffer": "^1.0.1"
}
},
"node_modules/webm-duration-fix/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/webpack": {
"version": "5.95.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz",
@@ -33901,11 +33840,6 @@
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"ebml-block": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/ebml-block/-/ebml-block-1.1.2.tgz",
"integrity": "sha512-HgNlIsRFP6D9VKU5atCeHRJY7XkJP8bOe8yEhd8NB7B3b4++VWTyauz6g650iiPmLfPLGlVpoJmGSgMfXDYusg=="
},
"ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
@@ -36203,11 +36137,6 @@
"rxjs": "^7.8.1"
}
},
"int64-buffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-1.0.1.tgz",
"integrity": "sha512-+3azY4pXrjAupJHU1V9uGERWlhoqNswJNji6aD/02xac7oxol508AsMC5lxKhEqyZeDFy3enq5OGWXF4u75hiw=="
},
"internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -37511,8 +37440,8 @@
}
},
"lib-jitsi-meet": {
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1973.0.0+64dcc15c/lib-jitsi-meet.tgz",
"integrity": "sha512-uwFKP+eZpxA8AXpv/XWk4qbyHNEovPS517Kz8gOhQSzYZpCnaN4smc3kfawInWw5da+GXtljVkkWXCWn3Lergw==",
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1980.0.0+34a32e86/lib-jitsi-meet.tgz",
"integrity": "sha512-NmjVrkhBgUhAHe84oEVGi5keXmO92RtVznchdPep6vJz9O2A6GPN9Ap+DZOoiK693bm9lRdzDIEIFn5GnlLfQg==",
"requires": {
"@jitsi/js-utils": "2.2.1",
"@jitsi/logger": "2.0.2",
@@ -37520,13 +37449,13 @@
"@jitsi/rtcstats": "9.7.0",
"@testrtc/watchrtc-sdk": "1.38.2",
"async-es": "3.2.4",
"base64-js": "1.3.1",
"base64-js": "1.5.1",
"current-executing-script": "0.1.3",
"jquery": "3.6.1",
"lodash-es": "4.17.21",
"sdp-transform": "2.3.0",
"strophe.js": "https://github.com/jitsi/strophejs/releases/download/v1.5-jitsi-3/strophe.js-1.5.0.tgz",
"uuid": "8.1.0",
"uuid": "8.3.2",
"webrtc-adapter": "8.1.1"
},
"dependencies": {
@@ -37547,16 +37476,6 @@
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
}
}
},
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"uuid": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
"integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg=="
}
}
},
@@ -42979,28 +42898,6 @@
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
},
"webm-duration-fix": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/webm-duration-fix/-/webm-duration-fix-1.0.4.tgz",
"integrity": "sha512-kvhmSmEnuohtK+j+mJswqCCM2ViKb9W8Ch0oAxcaeUvpok5CsMORQLnea+CYKDXPG6JH12H0CbRK85qhfeZLew==",
"requires": {
"buffer": "^6.0.3",
"ebml-block": "^1.1.2",
"events": "^3.3.0",
"int64-buffer": "^1.0.1"
},
"dependencies": {
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
}
}
},
"webpack": {
"version": "5.95.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz",

View File

@@ -67,7 +67,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1973.0.0+64dcc15c/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1980.0.0+34a32e86/lib-jitsi-meet.tgz",
"lodash-es": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -122,7 +122,6 @@
"util": "0.12.1",
"uuid": "8.3.2",
"wasm-check": "2.0.1",
"webm-duration-fix": "1.0.4",
"windows-iana": "3.1.0",
"zxcvbn": "4.4.2"
},

View File

@@ -72,11 +72,15 @@ export function getInitials(s?: string) {
/**
* Checks if the passed URL should be loaded with CORS.
*
* @param {string} url - The URL.
* @param {string | Function} url - The URL (on mobile we use a specific Icon component for avatars).
* @param {Array<string>} corsURLs - The URL pattern that matches a URL that needs to be handled with CORS.
* @returns {void}
* @returns {boolean}
*/
export function isCORSAvatarURL(url: string, corsURLs: Array<string> = []): boolean {
export function isCORSAvatarURL(url: string | Function, corsURLs: Array<string> = []): boolean {
if (typeof url === 'function') {
return false;
}
return corsURLs.some(pattern => url.startsWith(pattern));
}

View File

@@ -249,6 +249,8 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<IProps, IState> {
const { item } = flatListItem;
switch (item.type) {
// isCORSAvatarURL in this case is false
case INVITE_TYPES.PHONE:
return {
avatar: IconPhoneRinging,

View File

@@ -3,6 +3,7 @@ import { IStore } from '../../../app/types';
interface ILocalRecordingManager {
addAudioTrackToLocalRecording: (track: any) => void;
isRecordingLocally: () => boolean;
isSupported: () => boolean;
selfRecording: {
on: boolean;
withVideo: boolean;
@@ -40,6 +41,15 @@ const LocalRecordingManager: ILocalRecordingManager = {
*/
async startLocalRecording() { }, // eslint-disable-line @typescript-eslint/no-empty-function
/**
* Whether or not local recording is supported.
*
* @returns {boolean}
*/
isSupported() {
return false;
},
/**
* Whether or not we're currently recording locally.
*

View File

@@ -1,11 +1,12 @@
import i18next from 'i18next';
import { v4 as uuidV4 } from 'uuid';
import fixWebmDuration from 'webm-duration-fix';
import { IStore } from '../../../app/types';
import { getRoomName } from '../../../base/conference/functions';
import { MEDIA_TYPE } from '../../../base/media/constants';
import { getLocalTrack, getTrackState } from '../../../base/tracks/functions';
import { isMobileBrowser } from '../../../base/environment/utils';
import { browser } from '../../../base/lib-jitsi-meet';
import { isEmbedded } from '../../../base/util/embedUtils';
import { stopLocalVideoRecording } from '../../actions.any';
@@ -18,63 +19,54 @@ interface ILocalRecordingManager {
addAudioTrackToLocalRecording: (track: MediaStreamTrack) => void;
audioContext: AudioContext | undefined;
audioDestination: MediaStreamAudioDestinationNode | undefined;
fileHandle: FileSystemFileHandle | undefined;
getFilename: () => string;
initializeAudioMixer: () => void;
isRecordingLocally: () => boolean;
isSupported: () => boolean;
mediaType: string;
mixAudioStream: (stream: MediaStream) => void;
recorder: MediaRecorder | undefined;
recordingData: Blob[];
roomName: string;
saveRecording: (recordingData: Blob[], filename: string) => void;
selfRecording: ISelfRecording;
startLocalRecording: (store: IStore, onlySelf: boolean) => Promise<void>;
stopLocalRecording: () => void;
stream: MediaStream | undefined;
totalSize: number;
writableStream: FileSystemWritableFileStream | undefined;
}
const getMimeType = (): string => {
const possibleTypes = [
'video/webm;codecs=vp8'
];
for (const type of possibleTypes) {
if (MediaRecorder.isTypeSupported(type)) {
return type;
}
}
throw new Error('No MIME Type supported by MediaRecorder');
};
/**
* We want to use the MP4 container due to it not suffering from the resulting file
* not being seek-able.
*
* The choice of VP9 as the video codec and Opus as the audio codec is for compatibility.
* While Chrome does support avc1 and avc3 (we'd need the latter since the resolution can change)
* it's not supported across the board.
*/
const PREFERRED_MEDIA_TYPE = 'video/mp4;codecs=vp9,opus';
const VIDEO_BIT_RATE = 2500000; // 2.5Mbps in bits
const MAX_SIZE = 1073741824; // 1GB in bytes
// Lazily initialize.
let preferredMediaType: string;
const LocalRecordingManager: ILocalRecordingManager = {
recordingData: [],
recorder: undefined,
stream: undefined,
audioContext: undefined,
audioDestination: undefined,
roomName: '',
totalSize: MAX_SIZE,
selfRecording: {
on: false,
withVideo: false
},
fileHandle: undefined,
writableStream: undefined,
get mediaType() {
if (this.selfRecording.on && !this.selfRecording.withVideo) {
return 'audio/webm;';
}
if (!preferredMediaType) {
preferredMediaType = getMimeType();
}
return preferredMediaType;
return PREFERRED_MEDIA_TYPE;
},
/**
@@ -128,27 +120,6 @@ const LocalRecordingManager: ILocalRecordingManager = {
return `${this.roomName}_${timestamp}`;
},
/**
* Saves local recording to file.
*
* @param {Array} recordingData - The recording data.
* @param {string} filename - The name of the file.
* @returns {void}
* */
async saveRecording(recordingData, filename) {
// @ts-ignore
const blob = await fixWebmDuration(new Blob(recordingData, { type: this.mediaType }));
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
const extension = this.mediaType.slice(this.mediaType.indexOf('/') + 1, this.mediaType.indexOf(';'));
a.style.display = 'none';
a.href = url;
a.download = `${filename}.${extension}`;
a.click();
},
/**
* Stops local recording.
*
@@ -160,12 +131,10 @@ const LocalRecordingManager: ILocalRecordingManager = {
this.recorder = undefined;
this.audioContext = undefined;
this.audioDestination = undefined;
this.totalSize = MAX_SIZE;
setTimeout(() => {
if (this.recordingData.length > 0) {
this.saveRecording(this.recordingData, this.getFilename());
}
}, 1000);
this.writableStream?.close().then(() => {
this.fileHandle = undefined;
this.writableStream = undefined;
});
}
},
@@ -179,13 +148,23 @@ const LocalRecordingManager: ILocalRecordingManager = {
async startLocalRecording(store, onlySelf) {
const { dispatch, getState } = store;
this.roomName = getRoomName(getState()) ?? '';
// Get a handle to the file we are going to write.
const options = {
startIn: 'downloads',
suggestedName: `${this.getFilename()}.mp4`,
};
// @ts-expect-error
this.fileHandle = await window.showSaveFilePicker(options);
this.writableStream = await this.fileHandle?.createWritable();
// @ts-ignore
const supportsCaptureHandle = Boolean(navigator.mediaDevices.setCaptureHandleConfig) && !isEmbedded();
const tabId = uuidV4();
this.selfRecording.on = onlySelf;
this.recordingData = [];
this.roomName = getRoomName(getState()) ?? '';
let gdmStream: MediaStream = new MediaStream();
const tracks = getTrackState(getState());
@@ -280,13 +259,9 @@ const LocalRecordingManager: ILocalRecordingManager = {
mimeType: this.mediaType,
videoBitsPerSecond: VIDEO_BIT_RATE
});
this.recorder.addEventListener('dataavailable', e => {
if (e.data && e.data.size > 0) {
this.recordingData.push(e.data);
this.totalSize -= e.data.size;
if (this.totalSize <= 0) {
dispatch(stopLocalVideoRecording());
}
this.recorder.addEventListener('dataavailable', async e => {
if (this.recorder && e.data && e.data.size > 0) {
await this.writableStream?.write(e.data);
}
});
@@ -308,6 +283,22 @@ const LocalRecordingManager: ILocalRecordingManager = {
this.recorder.start(5000);
},
/**
* Whether or not local recording is supported.
*
* @returns {boolean}
*/
isSupported() {
return browser.isChromiumBased()
&& !browser.isElectron()
&& !browser.isReactNative()
&& !isMobileBrowser()
// @ts-expect-error
&& typeof window.showSaveFilePicker !== 'undefined'
&& MediaRecorder.isTypeSupported(PREFERRED_MEDIA_TYPE);
},
/**
* Whether or not we're currently recording locally.
*

View File

@@ -1,10 +1,9 @@
import i18next from 'i18next';
import { IReduxState, IStore } from '../app/types';
import { isMobileBrowser } from '../base/environment/utils';
import { MEET_FEATURES } from '../base/jwt/constants';
import { isJwtFeatureEnabled } from '../base/jwt/functions';
import { JitsiRecordingConstants, browser } from '../base/lib-jitsi-meet';
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
import { getSoundFileSrc } from '../base/media/functions';
import { getLocalParticipant, getRemoteParticipants } from '../base/participants/functions';
import { registerSound, unregisterSound } from '../base/sounds/actions';
@@ -152,8 +151,7 @@ export function getSessionStatusToShow(state: IReduxState, mode: string): string
* @returns {boolean} - Whether local recording is supported or not.
*/
export function supportsLocalRecording() {
return browser.isChromiumBased() && !browser.isElectron() && !isMobileBrowser()
&& navigator.product !== 'ReactNative';
return LocalRecordingManager.isSupported();
}
/**

View File

@@ -145,7 +145,7 @@ module:hook("pre-iq/full", function(event)
dial:tag("header", {
xmlns = "urn:xmpp:rayo:1",
name = OUT_INITIATOR_USER_ATTR_NAME,
value = user_id });
value = tostring(user_id)});
dial:up();
-- Add the initiator group information if it is present
@@ -153,7 +153,7 @@ module:hook("pre-iq/full", function(event)
dial:tag("header", {
xmlns = "urn:xmpp:rayo:1",
name = OUT_INITIATOR_GROUP_ATTR_NAME,
value = session.jitsi_meet_context_group });
value = tostring(session.jitsi_meet_context_group) });
dial:up();
end
end

View File

@@ -321,8 +321,11 @@ function starts_with_one_of(str, prefixes)
return false
end
function ends_with(str, ending)
if not str then
return false;
end
return ending == "" or str:sub(-#ending) == ending
end

View File

@@ -30,9 +30,7 @@ describe('Codec selection', () => {
// Check if p1 is sending VP9 and p2 is sending VP8 as per their codec preferences.
// Except on Firefox because it doesn't support VP9 encode.
const majorVersion = parseInt(p1.driver.capabilities.browserVersion || '0', 10);
if (p1.driver.isFirefox && majorVersion < 136) {
if (p1.driver.isFirefox) {
expect(await p1.execute(() => JitsiMeetJS.app.testing.isLocalCameraEncodingVp8())).toBe(true);
} else {
expect(await p1.execute(() => JitsiMeetJS.app.testing.isLocalCameraEncodingVp9())).toBe(true);
@@ -54,11 +52,11 @@ describe('Codec selection', () => {
// Check if media is playing on p3.
expect(await p3.execute(() => JitsiMeetJS.app.testing.isLargeVideoReceived())).toBe(true);
// Check if p1 is encoding in VP9, p2 in VP8 and p3 in AV1 as per their codec preferences.
// Except on Firefox because it doesn't support AV1/VP9 encode and AV1 decode.
const majorVersion = parseInt(p1.driver.capabilities.browserVersion || '0', 10);
if (p1.driver.isFirefox && majorVersion < 136) {
// Check if p1 is encoding in VP9, p2 in VP8 and p3 in AV1 as per their codec preferences.
// Except on Firefox because it doesn't support VP9 encode.
if (p1.driver.isFirefox) {
expect(await p1.execute(() => JitsiMeetJS.app.testing.isLocalCameraEncodingVp8())).toBe(true);
} else {
expect(await p1.execute(() => JitsiMeetJS.app.testing.isLocalCameraEncodingVp9())).toBe(true);
@@ -87,9 +85,7 @@ describe('Codec selection', () => {
const { p1, p2 } = ctx;
// Disable this test on Firefox because it doesn't support VP9 encode.
const majorVersion = parseInt(p1.driver.capabilities.browserVersion || '0', 10);
if (p1.driver.isFirefox && majorVersion < 136) {
if (p1.driver.isFirefox) {
return;
}