mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2025-12-30 03:12:29 +00:00
Implements Picture-in-Picture functionality for the Electron wrapper to maintain video engagement when users are not actively focused on the conference window. This feature addresses the need to keep users visually connected to the conference even when multitasking. Key features: - Automatic PiP mode activation and deactivation based on user interaction - Displays large video participant's stream or renders their avatar on canvas when video unavailable - Provides audio/video mute controls via MediaSession API directly in PiP window - Adds API events (_pip-requested) for Electron wrapper integration Implementation includes new pip feature module with Redux architecture, canvas-based avatar rendering with custom backgrounds support, and integration with existing mute/unmute logic. Depends on jitsi-meet-electron-sdk#479 for proper user gesture handling in Electron.
197 lines
4.9 KiB
TypeScript
197 lines
4.9 KiB
TypeScript
/**
|
|
* A helper function that behaves similar to Object.assign, but only reassigns a
|
|
* property in target if it's defined in source.
|
|
*
|
|
* @param {Object} target - The target object to assign the values into.
|
|
* @param {Object} source - The source object.
|
|
* @returns {Object}
|
|
*/
|
|
export function assignIfDefined(target: Object, source: Object) {
|
|
const to = Object(target);
|
|
|
|
for (const nextKey in source) {
|
|
if (source.hasOwnProperty(nextKey)) {
|
|
const value = source[nextKey as keyof typeof source];
|
|
|
|
if (typeof value !== 'undefined') {
|
|
to[nextKey] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return to;
|
|
}
|
|
|
|
const MATCH_OPERATOR_REGEXP = /[|\\{}()[\]^$+*?.-]/g;
|
|
|
|
/**
|
|
* Escape RegExp special characters.
|
|
*
|
|
* Based on https://github.com/sindresorhus/escape-string-regexp.
|
|
*
|
|
* @param {string} s - The regexp string to escape.
|
|
* @returns {string}
|
|
*/
|
|
export function escapeRegexp(s: string) {
|
|
if (typeof s !== 'string') {
|
|
throw new TypeError('Expected a string');
|
|
}
|
|
|
|
return s.replace(MATCH_OPERATOR_REGEXP, '\\$&');
|
|
}
|
|
|
|
/**
|
|
* Returns the base URL of the app.
|
|
*
|
|
* @param {Object} w - Window object to use instead of the built in one.
|
|
* @returns {string}
|
|
*/
|
|
export function getBaseUrl(w: typeof window = window) {
|
|
const doc = w.document;
|
|
const base = doc.querySelector('base');
|
|
|
|
if (base?.href) {
|
|
return base.href;
|
|
}
|
|
|
|
const { protocol, host } = w.location;
|
|
|
|
return `${protocol}//${host}`;
|
|
}
|
|
|
|
/**
|
|
* Returns the namespace for all global variables, functions, etc that we need.
|
|
*
|
|
* @returns {Object} The namespace.
|
|
*
|
|
* NOTE: After React-ifying everything this should be the only global.
|
|
*/
|
|
export function getJitsiMeetGlobalNS() {
|
|
if (!window.JitsiMeetJS) {
|
|
window.JitsiMeetJS = {};
|
|
}
|
|
|
|
if (!window.JitsiMeetJS.app) {
|
|
window.JitsiMeetJS.app = {};
|
|
}
|
|
|
|
return window.JitsiMeetJS.app;
|
|
}
|
|
|
|
/**
|
|
* Gets the Electron-specific global namespace.
|
|
*
|
|
* @returns {Object} The Electron namespace.
|
|
*/
|
|
export function getElectronGlobalNS() {
|
|
const globalNS = getJitsiMeetGlobalNS();
|
|
|
|
if (!globalNS.electron) {
|
|
globalNS.electron = {};
|
|
}
|
|
|
|
return globalNS.electron;
|
|
}
|
|
|
|
/**
|
|
* Returns the object that stores the connection times.
|
|
*
|
|
* @returns {Object} - The object that stores the connection times.
|
|
*/
|
|
export function getJitsiMeetGlobalNSConnectionTimes() {
|
|
const globalNS = getJitsiMeetGlobalNS();
|
|
|
|
if (!globalNS.connectionTimes) {
|
|
globalNS.connectionTimes = {};
|
|
}
|
|
|
|
return globalNS.connectionTimes;
|
|
}
|
|
|
|
/**
|
|
* Prints the error and reports it to the global error handler.
|
|
*
|
|
* @param {Error} e - The error object.
|
|
* @param {string} msg - A custom message to print in addition to the error.
|
|
* @returns {void}
|
|
*/
|
|
export function reportError(e: Error, msg = '') {
|
|
console.error(msg, e);
|
|
window.onerror?.(msg, undefined, undefined, undefined, e);
|
|
}
|
|
|
|
/**
|
|
* Adds alpha to a color css string.
|
|
*
|
|
* @param {string} color - The color string either in rgb... Or #... Format.
|
|
* @param {number} opacity -The opacity(alpha) to apply to the color. Can take a value between 0 and 1, including.
|
|
* @returns {string} - The color with applied alpha.
|
|
*/
|
|
export function setColorAlpha(color: string, opacity: number) {
|
|
if (!color) {
|
|
return `rgba(0, 0, 0, ${opacity})`;
|
|
}
|
|
|
|
let b, g, r;
|
|
|
|
try {
|
|
if (color.startsWith('rgb')) {
|
|
[ r, g, b ] = color.split('(')[1].split(')')[0].split(',').map(c => c.trim());
|
|
} else if (color.startsWith('#')) {
|
|
if (color.length === 4) {
|
|
[ r, g, b ] = parseShorthandColor(color);
|
|
} else {
|
|
r = parseInt(color.substring(1, 3), 16);
|
|
g = parseInt(color.substring(3, 5), 16);
|
|
b = parseInt(color.substring(5, 7), 16);
|
|
}
|
|
} else {
|
|
return color;
|
|
}
|
|
|
|
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
} catch {
|
|
return color;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the hexa rgb values for a shorthand css color.
|
|
*
|
|
* @param {string} color - The shorthand css color.
|
|
* @returns {Array<number>} - Array containing parsed r, g, b values of the color.
|
|
*/
|
|
function parseShorthandColor(color: string) {
|
|
let b, g, r;
|
|
|
|
r = color.substring(1, 2);
|
|
r += r;
|
|
r = parseInt(r, 16);
|
|
|
|
g = color.substring(2, 3);
|
|
g += g;
|
|
g = parseInt(g, 16);
|
|
|
|
b = color.substring(3, 4);
|
|
b += b;
|
|
b = parseInt(b, 16);
|
|
|
|
return [ r, g, b ];
|
|
}
|
|
|
|
/**
|
|
* Sorts an object by a sort function, same functionality as array.sort().
|
|
*
|
|
* @param {Object} object - The data object.
|
|
* @param {Function} callback - The sort function.
|
|
* @returns {void}
|
|
*/
|
|
export function objectSort(object: Object, callback: Function) {
|
|
return Object.entries(object)
|
|
.sort(([ , a ], [ , b ]) => callback(a, b))
|
|
.reduce((row, [ key, value ]) => {
|
|
return { ...row,
|
|
[key]: value };
|
|
}, {});
|
|
}
|