Skip to content

Commit

Permalink
Allow simulcast together with E2EE for supported Safari versions (#1117)
Browse files Browse the repository at this point in the history
* Disable simulcast for all iOS browsers when E2EE is enabled

* Create giant-days-run.md

* Disable simulcast only for unsupported browsers when e2ee enabled

* Update giant-days-run.md

* add osVersion tests

* cleanup
  • Loading branch information
lukasIO authored Apr 25, 2024
1 parent 4318954 commit 02f7a60
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .changeset/giant-days-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"livekit-client": patch
---

Allow simulcast together with E2EE for supported Safari versions
Also fixes the simulcast behaviour for iOS Chrome prior to 17.2
7 changes: 3 additions & 4 deletions src/room/participant/LocalParticipant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ import {
import type { DataPublishOptions } from '../types';
import {
Future,
isE2EESimulcastSupported,
isFireFox,
isSVCCodec,
isSafari,
isSafari17,
isWeb,
supportsAV1,
Expand Down Expand Up @@ -621,10 +621,9 @@ export default class LocalParticipant extends Participant {
...options,
};

// disable simulcast if e2ee is set on safari
if (isSafari() && this.roomOptions.e2ee) {
if (!isE2EESimulcastSupported() && this.roomOptions.e2ee) {
this.log.info(
`End-to-end encryption is set up, simulcast publishing will be disabled on Safari`,
`End-to-end encryption is set up, simulcast publishing will be disabled on Safari versions and iOS browsers running iOS < v17.2`,
{
...this.logContext,
},
Expand Down
30 changes: 29 additions & 1 deletion src/room/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,35 @@ export function isSafari17(): boolean {

export function isMobile(): boolean {
if (!isWeb()) return false;
return /Tablet|iPad|Mobile|Android|BlackBerry/.test(navigator.userAgent);

return (
// @ts-expect-error `userAgentData` is not yet part of typescript
navigator.userAgentData?.mobile ??
/Tablet|iPad|Mobile|Android|BlackBerry/.test(navigator.userAgent)
);
}

export function isE2EESimulcastSupported() {
const browser = getBrowser();
const supportedSafariVersion = '17.2'; // see https://bugs.webkit.org/show_bug.cgi?id=257803
if (browser) {
if (browser.name !== 'Safari' && browser.os !== 'iOS') {
return true;
} else if (
browser.os === 'iOS' &&
browser.osVersion &&
compareVersions(supportedSafariVersion, browser.osVersion) >= 0
) {
return true;
} else if (
browser.name === 'Safari' &&
compareVersions(supportedSafariVersion, browser.version) >= 0
) {
return true;
} else {
return false;
}
}
}

export function isWeb(): boolean {
Expand Down
4 changes: 4 additions & 0 deletions src/utils/browserParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ describe('browser parser', () => {
expect(details?.name).toBe('Safari');
expect(details?.version).toBe('16.3');
expect(details?.os).toBe('macOS');
expect(details?.osVersion).toBe('10.15.7');
});
it('parses Safari iOS correctly', () => {
const details = getBrowser(iOSSafariUA, true);
expect(details?.name).toBe('Safari');
expect(details?.version).toBe('16.5');
expect(details?.os).toBe('iOS');
expect(details?.osVersion).toBe('16.5.1');
});
it('parses Firefox correctly', () => {
const details = getBrowser(firefoxUA, true);
Expand All @@ -46,6 +48,7 @@ describe('browser parser', () => {
expect(details?.name).toBe('Firefox');
expect(details?.version).toBe('115.0');
expect(details?.os).toBe('iOS');
expect(details?.osVersion).toBe('13.4.1');
});
it('parses Chrome correctly', () => {
const details = getBrowser(chromeUA, true);
Expand All @@ -57,6 +60,7 @@ describe('browser parser', () => {
expect(details?.name).toBe('Chrome');
expect(details?.version).toBe('115.0.5790.130');
expect(details?.os).toBe('iOS');
expect(details?.osVersion).toBe('16.5');
});
it('detects brave as chromium based', () => {
const details = getBrowser(braveUA, true);
Expand Down
12 changes: 11 additions & 1 deletion src/utils/browserParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ export type BrowserDetails = {
name: DetectableBrowser;
version: string;
os?: DetectableOS;
osVersion?: string;
};

let browserDetails: BrowserDetails | undefined;

/**
* @internal
*/
export function getBrowser(userAgent?: string, force = true) {
export function getBrowser(userAgent?: string, force = true): BrowserDetails | undefined {
if (typeof userAgent === 'undefined' && typeof navigator === 'undefined') {
return;
}
Expand All @@ -37,6 +38,7 @@ const browsersList = [
name: 'Firefox',
version: getMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, ua),
os: ua.toLowerCase().includes('fxios') ? 'iOS' : undefined,
osVersion: getOSVersion(ua),
};
return browser;
},
Expand All @@ -48,6 +50,7 @@ const browsersList = [
name: 'Chrome',
version: getMatch(/(?:chrome|chromium|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua),
os: ua.toLowerCase().includes('crios') ? 'iOS' : undefined,
osVersion: getOSVersion(ua),
};

return browser;
Expand All @@ -61,6 +64,7 @@ const browsersList = [
name: 'Safari',
version: getMatch(commonVersionIdentifier, ua),
os: ua.includes('mobile/') ? 'iOS' : 'macOS',
osVersion: getOSVersion(ua),
};

return browser;
Expand All @@ -72,3 +76,9 @@ function getMatch(exp: RegExp, ua: string, id = 1) {
const match = ua.match(exp);
return (match && match.length >= id && match[id]) || '';
}

function getOSVersion(ua: string) {
return ua.includes('mac os')
? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.')
: undefined;
}

0 comments on commit 02f7a60

Please sign in to comment.