mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-04-02 00:07:56 +01:00
calling: add internal preferences for DRED, bitrate, VP9, sfu url
This commit is contained in:
@@ -56,6 +56,9 @@ export type SemverKeyType = ArrayValues<typeof SemverKeys>;
|
|||||||
|
|
||||||
const ScalarKeys = [
|
const ScalarKeys = [
|
||||||
'desktop.callQualitySurveyPPM',
|
'desktop.callQualitySurveyPPM',
|
||||||
|
'desktop.calling.dredDuration.alpha',
|
||||||
|
'desktop.calling.dredDuration.beta',
|
||||||
|
'desktop.calling.dredDuration.prod',
|
||||||
'desktop.clientExpiration',
|
'desktop.clientExpiration',
|
||||||
'desktop.internalUser',
|
'desktop.internalUser',
|
||||||
'desktop.loggingErrorToasts',
|
'desktop.loggingErrorToasts',
|
||||||
|
|||||||
@@ -647,6 +647,18 @@ export default {
|
|||||||
},
|
},
|
||||||
cqsTestMode: false,
|
cqsTestMode: false,
|
||||||
setCqsTestMode: action('setCqsTestMode'),
|
setCqsTestMode: action('setCqsTestMode'),
|
||||||
|
dredDuration: 0,
|
||||||
|
setDredDuration: action('setDredDuration'),
|
||||||
|
directMaxBitrate: 1000000,
|
||||||
|
setDirectMaxBitrate: action('setDirectMaxBitrate'),
|
||||||
|
isDirectVp9Enabled: true,
|
||||||
|
setIsDirectVp9Enabled: action('setIsDirectVp9Enabled'),
|
||||||
|
groupMaxBitrate: 1000000,
|
||||||
|
setGroupMaxBitrate: action('setGroupMaxBitrate'),
|
||||||
|
isGroupVp9Enabled: false,
|
||||||
|
setIsGroupVp9Enabled: action('setIsDirectVp9Enabled'),
|
||||||
|
sfuUrl: 'https://sfu.voip.signal.org',
|
||||||
|
setSfuUrl: action('setSfuUrl'),
|
||||||
} satisfies PropsType,
|
} satisfies PropsType,
|
||||||
} satisfies Meta<PropsType>;
|
} satisfies Meta<PropsType>;
|
||||||
|
|
||||||
|
|||||||
@@ -210,6 +210,14 @@ export type PropsDataType = {
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
donationReceipts: ReadonlyArray<DonationReceipt>;
|
donationReceipts: ReadonlyArray<DonationReceipt>;
|
||||||
|
|
||||||
|
// calling internal preferences
|
||||||
|
dredDuration: number | undefined;
|
||||||
|
isDirectVp9Enabled: boolean | undefined;
|
||||||
|
directMaxBitrate: number | undefined;
|
||||||
|
isGroupVp9Enabled: boolean | undefined;
|
||||||
|
groupMaxBitrate: number | undefined;
|
||||||
|
sfuUrl: string | undefined;
|
||||||
} & Omit<MediaDeviceSettings, 'availableCameras'>;
|
} & Omit<MediaDeviceSettings, 'availableCameras'>;
|
||||||
|
|
||||||
type PropsFunctionType = {
|
type PropsFunctionType = {
|
||||||
@@ -345,6 +353,12 @@ type PropsFunctionType = {
|
|||||||
) => Promise<ReadonlyArray<RowType<object>>>;
|
) => Promise<ReadonlyArray<RowType<object>>>;
|
||||||
cqsTestMode: boolean;
|
cqsTestMode: boolean;
|
||||||
setCqsTestMode: (value: boolean) => void;
|
setCqsTestMode: (value: boolean) => void;
|
||||||
|
setDredDuration: (value: number | undefined) => void;
|
||||||
|
setIsDirectVp9Enabled: (value: boolean | undefined) => void;
|
||||||
|
setDirectMaxBitrate: (value: number | undefined) => void;
|
||||||
|
setIsGroupVp9Enabled: (value: boolean | undefined) => void;
|
||||||
|
setGroupMaxBitrate: (value: number | undefined) => void;
|
||||||
|
setSfuUrl: (value: string | undefined) => void;
|
||||||
|
|
||||||
// Localization
|
// Localization
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
@@ -554,6 +568,18 @@ export function Preferences({
|
|||||||
__dangerouslyRunAbitraryReadOnlySqlQuery,
|
__dangerouslyRunAbitraryReadOnlySqlQuery,
|
||||||
cqsTestMode,
|
cqsTestMode,
|
||||||
setCqsTestMode,
|
setCqsTestMode,
|
||||||
|
setDredDuration,
|
||||||
|
dredDuration,
|
||||||
|
setIsDirectVp9Enabled,
|
||||||
|
isDirectVp9Enabled,
|
||||||
|
setDirectMaxBitrate,
|
||||||
|
directMaxBitrate,
|
||||||
|
setIsGroupVp9Enabled,
|
||||||
|
isGroupVp9Enabled,
|
||||||
|
setGroupMaxBitrate,
|
||||||
|
groupMaxBitrate,
|
||||||
|
setSfuUrl,
|
||||||
|
sfuUrl,
|
||||||
}: PropsType): React.JSX.Element {
|
}: PropsType): React.JSX.Element {
|
||||||
const storiesId = useId();
|
const storiesId = useId();
|
||||||
const themeSelectId = useId();
|
const themeSelectId = useId();
|
||||||
@@ -2333,6 +2359,18 @@ export function Preferences({
|
|||||||
}
|
}
|
||||||
cqsTestMode={cqsTestMode}
|
cqsTestMode={cqsTestMode}
|
||||||
setCqsTestMode={setCqsTestMode}
|
setCqsTestMode={setCqsTestMode}
|
||||||
|
dredDuration={dredDuration}
|
||||||
|
setDredDuration={setDredDuration}
|
||||||
|
setIsDirectVp9Enabled={setIsDirectVp9Enabled}
|
||||||
|
isDirectVp9Enabled={isDirectVp9Enabled}
|
||||||
|
setDirectMaxBitrate={setDirectMaxBitrate}
|
||||||
|
directMaxBitrate={directMaxBitrate}
|
||||||
|
setIsGroupVp9Enabled={setIsGroupVp9Enabled}
|
||||||
|
isGroupVp9Enabled={isGroupVp9Enabled}
|
||||||
|
setGroupMaxBitrate={setGroupMaxBitrate}
|
||||||
|
groupMaxBitrate={groupMaxBitrate}
|
||||||
|
sfuUrl={sfuUrl}
|
||||||
|
setSfuUrl={setSfuUrl}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
contentsRef={settingsPaneRef}
|
contentsRef={settingsPaneRef}
|
||||||
|
|||||||
@@ -40,6 +40,19 @@ export function PreferencesInternal({
|
|||||||
__dangerouslyRunAbitraryReadOnlySqlQuery,
|
__dangerouslyRunAbitraryReadOnlySqlQuery,
|
||||||
cqsTestMode,
|
cqsTestMode,
|
||||||
setCqsTestMode,
|
setCqsTestMode,
|
||||||
|
|
||||||
|
dredDuration,
|
||||||
|
setDredDuration,
|
||||||
|
isDirectVp9Enabled,
|
||||||
|
setIsDirectVp9Enabled,
|
||||||
|
directMaxBitrate,
|
||||||
|
setDirectMaxBitrate,
|
||||||
|
isGroupVp9Enabled,
|
||||||
|
setIsGroupVp9Enabled,
|
||||||
|
groupMaxBitrate,
|
||||||
|
setGroupMaxBitrate,
|
||||||
|
sfuUrl,
|
||||||
|
setSfuUrl,
|
||||||
}: {
|
}: {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
validateBackup: () => Promise<BackupValidationResultType>;
|
validateBackup: () => Promise<BackupValidationResultType>;
|
||||||
@@ -65,6 +78,18 @@ export function PreferencesInternal({
|
|||||||
) => Promise<ReadonlyArray<RowType<object>>>;
|
) => Promise<ReadonlyArray<RowType<object>>>;
|
||||||
cqsTestMode: boolean;
|
cqsTestMode: boolean;
|
||||||
setCqsTestMode: (value: boolean) => void;
|
setCqsTestMode: (value: boolean) => void;
|
||||||
|
dredDuration: number | undefined;
|
||||||
|
setDredDuration: (value: number | undefined) => void;
|
||||||
|
isDirectVp9Enabled: boolean | undefined;
|
||||||
|
setIsDirectVp9Enabled: (value: boolean | undefined) => void;
|
||||||
|
directMaxBitrate: number | undefined;
|
||||||
|
setDirectMaxBitrate: (value: number | undefined) => void;
|
||||||
|
isGroupVp9Enabled: boolean | undefined;
|
||||||
|
setIsGroupVp9Enabled: (value: boolean | undefined) => void;
|
||||||
|
groupMaxBitrate: number | undefined;
|
||||||
|
setGroupMaxBitrate: (value: number | undefined) => void;
|
||||||
|
sfuUrl: string | undefined;
|
||||||
|
setSfuUrl: (value: string | undefined) => void;
|
||||||
}): React.JSX.Element {
|
}): React.JSX.Element {
|
||||||
const [messageCountBySchemaVersion, setMessageCountBySchemaVersion] =
|
const [messageCountBySchemaVersion, setMessageCountBySchemaVersion] =
|
||||||
useState<MessageCountBySchemaVersionType>();
|
useState<MessageCountBySchemaVersionType>();
|
||||||
@@ -89,6 +114,57 @@ export function PreferencesInternal({
|
|||||||
RowType<object>
|
RowType<object>
|
||||||
> | null>(null);
|
> | null>(null);
|
||||||
|
|
||||||
|
const stripAndParseString = (input: string): number | undefined => {
|
||||||
|
const stripped = input.replace(/\D/g, '');
|
||||||
|
return stripped.length !== 0 ? parseInt(stripped, 10) : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDredDurationUpdate = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
const parsed = stripAndParseString(input);
|
||||||
|
if (parsed) {
|
||||||
|
setDredDuration(Math.min(100, parsed));
|
||||||
|
} else {
|
||||||
|
setDredDuration(undefined);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setDredDuration]
|
||||||
|
);
|
||||||
|
const handleDirectMaxBitrateUpdate = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
setDirectMaxBitrate(stripAndParseString(input));
|
||||||
|
},
|
||||||
|
[setDirectMaxBitrate]
|
||||||
|
);
|
||||||
|
const handleGroupMaxBitrateUpdate = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
setGroupMaxBitrate(stripAndParseString(input));
|
||||||
|
},
|
||||||
|
[setGroupMaxBitrate]
|
||||||
|
);
|
||||||
|
const handleSfuUrlUpdate = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
const url = input.trim();
|
||||||
|
setSfuUrl(url.length !== 0 ? url : undefined);
|
||||||
|
},
|
||||||
|
[setSfuUrl]
|
||||||
|
);
|
||||||
|
const handleResetCallingOverrides = useCallback(() => {
|
||||||
|
setDredDuration(undefined);
|
||||||
|
setIsDirectVp9Enabled(undefined);
|
||||||
|
setDirectMaxBitrate(undefined);
|
||||||
|
setIsGroupVp9Enabled(undefined);
|
||||||
|
setGroupMaxBitrate(undefined);
|
||||||
|
setSfuUrl(undefined);
|
||||||
|
}, [
|
||||||
|
setDredDuration,
|
||||||
|
setIsDirectVp9Enabled,
|
||||||
|
setDirectMaxBitrate,
|
||||||
|
setIsGroupVp9Enabled,
|
||||||
|
setGroupMaxBitrate,
|
||||||
|
setSfuUrl,
|
||||||
|
]);
|
||||||
|
|
||||||
const validateBackup = useCallback(async () => {
|
const validateBackup = useCallback(async () => {
|
||||||
setIsValidationPending(true);
|
setIsValidationPending(true);
|
||||||
setValidationResult(undefined);
|
setValidationResult(undefined);
|
||||||
@@ -559,6 +635,94 @@ export function PreferencesInternal({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</SettingsRow>
|
</SettingsRow>
|
||||||
|
<SettingsRow title="Calling General">
|
||||||
|
<FlowingSettingsControl>
|
||||||
|
<div className="Preferences__two-thirds-flow">
|
||||||
|
Clear custom calling preferences
|
||||||
|
</div>
|
||||||
|
<div className="Preferences__one-third-flow Preferences__one-third-flow--justify-end">
|
||||||
|
<AxoButton.Root
|
||||||
|
variant="destructive"
|
||||||
|
size="lg"
|
||||||
|
onClick={handleResetCallingOverrides}
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</AxoButton.Root>
|
||||||
|
</div>
|
||||||
|
</FlowingSettingsControl>
|
||||||
|
<FlowingSettingsControl>
|
||||||
|
<div className="Preferences__two-thirds-flow">
|
||||||
|
DRED Duration (0 - 100)
|
||||||
|
</div>
|
||||||
|
<div className="Preferences__one-third-flow Preferences__one-third-flow--justify-end">
|
||||||
|
<AutoSizeTextArea
|
||||||
|
i18n={i18n}
|
||||||
|
value={dredDuration?.toString(10)}
|
||||||
|
onChange={handleDredDurationUpdate}
|
||||||
|
placeholder="0 - 100"
|
||||||
|
moduleClassName="Preferences__ReadonlySqlPlayground__Textarea"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FlowingSettingsControl>
|
||||||
|
</SettingsRow>
|
||||||
|
<SettingsRow title="Direct Calls">
|
||||||
|
<FlowingSettingsControl>
|
||||||
|
<div className="Preferences__two-thirds-flow">Enable VP9</div>
|
||||||
|
<div className="Preferences__one-third-flow Preferences__one-third-flow--justify-end">
|
||||||
|
<AxoSwitch.Root
|
||||||
|
checked={isDirectVp9Enabled ?? true}
|
||||||
|
onCheckedChange={setIsDirectVp9Enabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FlowingSettingsControl>
|
||||||
|
<FlowingSettingsControl>
|
||||||
|
<div className="Preferences__two-thirds-flow">Max bitrate</div>
|
||||||
|
<div className="Preferences__one-third-flow Preferences__one-third-flow--justify-end">
|
||||||
|
<AutoSizeTextArea
|
||||||
|
i18n={i18n}
|
||||||
|
value={directMaxBitrate?.toString(10)}
|
||||||
|
onChange={handleDirectMaxBitrateUpdate}
|
||||||
|
placeholder="Default"
|
||||||
|
moduleClassName="Preferences__ReadonlySqlPlayground__Textarea"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FlowingSettingsControl>
|
||||||
|
</SettingsRow>
|
||||||
|
<SettingsRow title="Group/Adhoc Calls">
|
||||||
|
<FlowingSettingsControl>
|
||||||
|
<div className="Preferences__two-thirds-flow">Enable VP9</div>
|
||||||
|
<div className="Preferences__one-third-flow Preferences__one-third-flow--justify-end">
|
||||||
|
<AxoSwitch.Root
|
||||||
|
checked={isGroupVp9Enabled ?? false}
|
||||||
|
onCheckedChange={setIsGroupVp9Enabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FlowingSettingsControl>
|
||||||
|
<FlowingSettingsControl>
|
||||||
|
<div className="Preferences__two-thirds-flow">Max bitrate</div>
|
||||||
|
<div className="Preferences__one-third-flow Preferences__one-third-flow--justify-end">
|
||||||
|
<AutoSizeTextArea
|
||||||
|
i18n={i18n}
|
||||||
|
value={groupMaxBitrate?.toString(10)}
|
||||||
|
onChange={handleGroupMaxBitrateUpdate}
|
||||||
|
placeholder="Default"
|
||||||
|
moduleClassName="Preferences__ReadonlySqlPlayground__Textarea"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FlowingSettingsControl>
|
||||||
|
<FlowingSettingsControl>
|
||||||
|
<div className="Preferences__one-third-flow">SFU URL</div>
|
||||||
|
<div className="Preferences__two-thirds-flow Preferences__two-thirds-flow--justify-end">
|
||||||
|
<AutoSizeTextArea
|
||||||
|
i18n={i18n}
|
||||||
|
value={sfuUrl}
|
||||||
|
onChange={handleSfuUrlUpdate}
|
||||||
|
placeholder="https://sfu.voip.signal.org"
|
||||||
|
moduleClassName="Preferences__ReadonlySqlPlayground__Textarea"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FlowingSettingsControl>
|
||||||
|
</SettingsRow>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,9 @@ import {
|
|||||||
isCallFailure,
|
isCallFailure,
|
||||||
shouldShowCallQualitySurvey,
|
shouldShowCallQualitySurvey,
|
||||||
} from '../util/callQualitySurvey.dom.js';
|
} from '../util/callQualitySurvey.dom.js';
|
||||||
|
import * as RemoteConfig from '../RemoteConfig.dom.js';
|
||||||
|
import { isAlpha, isBeta, isProduction } from '../util/version.std.js';
|
||||||
|
import { parseIntOrThrow } from '../util/parseIntOrThrow.std.js';
|
||||||
|
|
||||||
const { i18n } = window.SignalContext;
|
const { i18n } = window.SignalContext;
|
||||||
|
|
||||||
@@ -572,8 +575,11 @@ export class CallingClass {
|
|||||||
#localPreviewContainer: HTMLDivElement | undefined;
|
#localPreviewContainer: HTMLDivElement | undefined;
|
||||||
#localPreview: HTMLVideoElement | undefined;
|
#localPreview: HTMLVideoElement | undefined;
|
||||||
#reduxInterface?: CallingReduxInterface;
|
#reduxInterface?: CallingReduxInterface;
|
||||||
|
#_sfuUrl?: string;
|
||||||
|
|
||||||
public _sfuUrl?: string;
|
public get sfuUrl(): string | undefined {
|
||||||
|
return itemStorage.get('sfuUrl') ?? this.#_sfuUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public _iceServerOverride?: GetIceServersResultType | string;
|
public _iceServerOverride?: GetIceServersResultType | string;
|
||||||
|
|
||||||
@@ -606,7 +612,7 @@ export class CallingClass {
|
|||||||
throw new Error('CallingClass.initialize: Invalid uxActions.');
|
throw new Error('CallingClass.initialize: Invalid uxActions.');
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sfuUrl = sfuUrl;
|
this.#_sfuUrl = sfuUrl;
|
||||||
|
|
||||||
RingRTC.setConfig({
|
RingRTC.setConfig({
|
||||||
field_trials: undefined,
|
field_trials: undefined,
|
||||||
@@ -851,11 +857,11 @@ export class CallingClass {
|
|||||||
|
|
||||||
async createCallLink(): Promise<CallLinkType> {
|
async createCallLink(): Promise<CallLinkType> {
|
||||||
strictAssert(
|
strictAssert(
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
'createCallLink() missing SFU URL; not creating call link'
|
'createCallLink() missing SFU URL; not creating call link'
|
||||||
);
|
);
|
||||||
|
|
||||||
const sfuUrl = this._sfuUrl;
|
const { sfuUrl } = this;
|
||||||
const userId = Aci.parseFromServiceIdString(
|
const userId = Aci.parseFromServiceIdString(
|
||||||
itemStorage.user.getCheckedAci()
|
itemStorage.user.getCheckedAci()
|
||||||
);
|
);
|
||||||
@@ -936,11 +942,11 @@ export class CallingClass {
|
|||||||
|
|
||||||
async deleteCallLink(callLink: CallLinkType): Promise<void> {
|
async deleteCallLink(callLink: CallLinkType): Promise<void> {
|
||||||
strictAssert(
|
strictAssert(
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
'createCallLink() missing SFU URL; not deleting call link'
|
'createCallLink() missing SFU URL; not deleting call link'
|
||||||
);
|
);
|
||||||
|
|
||||||
const sfuUrl = this._sfuUrl;
|
const { sfuUrl } = this;
|
||||||
const logId = `deleteCallLink(${callLink.roomId})`;
|
const logId = `deleteCallLink(${callLink.roomId})`;
|
||||||
log.info(logId);
|
log.info(logId);
|
||||||
|
|
||||||
@@ -973,10 +979,10 @@ export class CallingClass {
|
|||||||
name: string
|
name: string
|
||||||
): Promise<CallLinkStateType> {
|
): Promise<CallLinkStateType> {
|
||||||
strictAssert(
|
strictAssert(
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
'updateCallLinkName() missing SFU URL; not update call link name'
|
'updateCallLinkName() missing SFU URL; not update call link name'
|
||||||
);
|
);
|
||||||
const sfuUrl = this._sfuUrl;
|
const { sfuUrl } = this;
|
||||||
const logId = `updateCallLinkName(${callLink.roomId})`;
|
const logId = `updateCallLinkName(${callLink.roomId})`;
|
||||||
|
|
||||||
log.info(`${logId}: Updating call link name`);
|
log.info(`${logId}: Updating call link name`);
|
||||||
@@ -1011,10 +1017,10 @@ export class CallingClass {
|
|||||||
restrictions: CallLinkRestrictions
|
restrictions: CallLinkRestrictions
|
||||||
): Promise<CallLinkStateType> {
|
): Promise<CallLinkStateType> {
|
||||||
strictAssert(
|
strictAssert(
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
'updateCallLinkRestrictions() missing SFU URL; not update call link restrictions'
|
'updateCallLinkRestrictions() missing SFU URL; not update call link restrictions'
|
||||||
);
|
);
|
||||||
const sfuUrl = this._sfuUrl;
|
const { sfuUrl } = this;
|
||||||
const logId = `updateCallLinkRestrictions(${callLink.roomId})`;
|
const logId = `updateCallLinkRestrictions(${callLink.roomId})`;
|
||||||
|
|
||||||
log.info(`${logId}: Updating call link restrictions`);
|
log.info(`${logId}: Updating call link restrictions`);
|
||||||
@@ -1054,7 +1060,7 @@ export class CallingClass {
|
|||||||
async readCallLink(
|
async readCallLink(
|
||||||
callLinkRootKey: CallLinkRootKey
|
callLinkRootKey: CallLinkRootKey
|
||||||
): Promise<CallLinkStateType | null> {
|
): Promise<CallLinkStateType | null> {
|
||||||
if (!this._sfuUrl) {
|
if (!this.sfuUrl) {
|
||||||
throw new Error('readCallLink() missing SFU URL; not handling call link');
|
throw new Error('readCallLink() missing SFU URL; not handling call link');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1066,7 +1072,7 @@ export class CallingClass {
|
|||||||
await getCallLinkAuthCredentialPresentation(callLinkRootKey);
|
await getCallLinkAuthCredentialPresentation(callLinkRootKey);
|
||||||
|
|
||||||
const result = await RingRTC.readCallLink(
|
const result = await RingRTC.readCallLink(
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
authCredentialPresentation.serialize(),
|
authCredentialPresentation.serialize(),
|
||||||
callLinkRootKey
|
callLinkRootKey
|
||||||
);
|
);
|
||||||
@@ -1315,7 +1321,7 @@ export class CallingClass {
|
|||||||
return statefulPeekInfo;
|
return statefulPeekInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._sfuUrl) {
|
if (!this.sfuUrl) {
|
||||||
throw new Error('Missing SFU URL; not peeking group call');
|
throw new Error('Missing SFU URL; not peeking group call');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1338,7 +1344,7 @@ export class CallingClass {
|
|||||||
const membershipProof = Bytes.fromString(proof);
|
const membershipProof = Bytes.fromString(proof);
|
||||||
|
|
||||||
return RingRTC.peekGroupCall(
|
return RingRTC.peekGroupCall(
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
membershipProof,
|
membershipProof,
|
||||||
this.#getGroupCallMembers(conversationId)
|
this.#getGroupCallMembers(conversationId)
|
||||||
);
|
);
|
||||||
@@ -1360,7 +1366,7 @@ export class CallingClass {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._sfuUrl) {
|
if (!this.sfuUrl) {
|
||||||
throw new Error('Missing SFU URL; not peeking call link call');
|
throw new Error('Missing SFU URL; not peeking call link call');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1369,7 +1375,7 @@ export class CallingClass {
|
|||||||
await getCallLinkAuthCredentialPresentation(callLinkRootKey);
|
await getCallLinkAuthCredentialPresentation(callLinkRootKey);
|
||||||
|
|
||||||
const result = await RingRTC.peekCallLinkCall(
|
const result = await RingRTC.peekCallLinkCall(
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
authCredentialPresentation.serialize(),
|
authCredentialPresentation.serialize(),
|
||||||
callLinkRootKey
|
callLinkRootKey
|
||||||
);
|
);
|
||||||
@@ -1412,7 +1418,7 @@ export class CallingClass {
|
|||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._sfuUrl) {
|
if (!this.sfuUrl) {
|
||||||
throw new Error('Missing SFU URL; not connecting group call');
|
throw new Error('Missing SFU URL; not connecting group call');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1420,16 +1426,16 @@ export class CallingClass {
|
|||||||
log.info(logId);
|
log.info(logId);
|
||||||
|
|
||||||
const groupIdBuffer = Bytes.fromBase64(groupId);
|
const groupIdBuffer = Bytes.fromBase64(groupId);
|
||||||
const dredDuration = 0;
|
|
||||||
|
|
||||||
let isRequestingMembershipProof = false;
|
let isRequestingMembershipProof = false;
|
||||||
|
const config = this.#getRemoteAndOverrideConfigValues();
|
||||||
|
|
||||||
const outerGroupCall = RingRTC.getGroupCall(
|
const outerGroupCall = RingRTC.getGroupCall(
|
||||||
groupIdBuffer,
|
groupIdBuffer,
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
new Uint8Array(),
|
new Uint8Array(),
|
||||||
AUDIO_LEVEL_INTERVAL_MS,
|
AUDIO_LEVEL_INTERVAL_MS,
|
||||||
dredDuration,
|
config.dredDuration,
|
||||||
{
|
{
|
||||||
...this.#getGroupCallObserver(conversationId, CallMode.Group),
|
...this.#getGroupCallObserver(conversationId, CallMode.Group),
|
||||||
async requestMembershipProof(groupCall) {
|
async requestMembershipProof(groupCall) {
|
||||||
@@ -1496,23 +1502,22 @@ export class CallingClass {
|
|||||||
const logId = `connectCallLinkCall(${roomId}`;
|
const logId = `connectCallLinkCall(${roomId}`;
|
||||||
log.info(logId);
|
log.info(logId);
|
||||||
|
|
||||||
if (!this._sfuUrl) {
|
if (!this.sfuUrl) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${logId}: Missing SFU URL; not connecting group call link call`
|
`${logId}: Missing SFU URL; not connecting group call link call`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const config = this.#getRemoteAndOverrideConfigValues();
|
||||||
const dredDuration = 0;
|
|
||||||
|
|
||||||
const outerGroupCall = RingRTC.getCallLinkCall(
|
const outerGroupCall = RingRTC.getCallLinkCall(
|
||||||
this._sfuUrl,
|
this.sfuUrl,
|
||||||
endorsementsPublicKey,
|
endorsementsPublicKey,
|
||||||
authCredentialPresentation.serialize(),
|
authCredentialPresentation.serialize(),
|
||||||
callLinkRootKey,
|
callLinkRootKey,
|
||||||
adminPasskey,
|
adminPasskey,
|
||||||
new Uint8Array(),
|
new Uint8Array(),
|
||||||
AUDIO_LEVEL_INTERVAL_MS,
|
AUDIO_LEVEL_INTERVAL_MS,
|
||||||
dredDuration,
|
config.dredDuration,
|
||||||
this.#getGroupCallObserver(roomId, CallMode.Adhoc)
|
this.#getGroupCallObserver(roomId, CallMode.Adhoc)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -3863,6 +3868,59 @@ export class CallingClass {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#getRemoteAndOverrideConfigValues(): {
|
||||||
|
dredDuration: number | undefined;
|
||||||
|
isDirectVp9Enabled: boolean | undefined;
|
||||||
|
directMaxBitrate: number | undefined;
|
||||||
|
isGroupVp9Enabled: boolean | undefined;
|
||||||
|
groupMaxBitrate: number | undefined;
|
||||||
|
} {
|
||||||
|
function dredDuration(version: string): number | undefined {
|
||||||
|
const override = itemStorage.get('dredDuration');
|
||||||
|
if (override) {
|
||||||
|
return override;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isProduction(version)) {
|
||||||
|
return tryParseInt(
|
||||||
|
RemoteConfig.getValue('desktop.calling.dredDuration.prod')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBeta(version)) {
|
||||||
|
return tryParseInt(
|
||||||
|
RemoteConfig.getValue('desktop.calling.dredDuration.beta')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAlpha(version)) {
|
||||||
|
return tryParseInt(
|
||||||
|
RemoteConfig.getValue('desktop.calling.dredDuration.alpha')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryParseInt(v: string | undefined): number | undefined {
|
||||||
|
try {
|
||||||
|
return parseIntOrThrow(v, 'invalid');
|
||||||
|
} catch (e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const version = window.SignalContext.getVersion();
|
||||||
|
|
||||||
|
return {
|
||||||
|
dredDuration: dredDuration(version),
|
||||||
|
isDirectVp9Enabled: itemStorage.get('isDirectVp9Enabled'),
|
||||||
|
directMaxBitrate: itemStorage.get('directMaxBitrate'),
|
||||||
|
isGroupVp9Enabled: itemStorage.get('isGroupVp9Enabled'),
|
||||||
|
groupMaxBitrate: itemStorage.get('directMaxBitrate'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async #getIceServers(): Promise<Array<IceServerType>> {
|
async #getIceServers(): Promise<Array<IceServerType>> {
|
||||||
function iceServerConfigToList(
|
function iceServerConfigToList(
|
||||||
iceServerConfig: GetIceServersResultType
|
iceServerConfig: GetIceServersResultType
|
||||||
@@ -3964,6 +4022,7 @@ export class CallingClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const iceServers = await this.#getIceServers();
|
const iceServers = await this.#getIceServers();
|
||||||
|
const config = this.#getRemoteAndOverrideConfigValues();
|
||||||
|
|
||||||
// We do this again, since getIceServers is a call that can take some time
|
// We do this again, since getIceServers is a call that can take some time
|
||||||
if (call.endedReason) {
|
if (call.endedReason) {
|
||||||
@@ -3984,7 +4043,7 @@ export class CallingClass {
|
|||||||
hideIp: shouldRelayCalls || isContactUntrusted,
|
hideIp: shouldRelayCalls || isContactUntrusted,
|
||||||
dataMode: DataMode.Normal,
|
dataMode: DataMode.Normal,
|
||||||
audioLevelsIntervalMillis: AUDIO_LEVEL_INTERVAL_MS,
|
audioLevelsIntervalMillis: AUDIO_LEVEL_INTERVAL_MS,
|
||||||
dredDuration: 0,
|
dredDuration: config.dredDuration,
|
||||||
};
|
};
|
||||||
|
|
||||||
log.info('CallingClass.handleStartCall(): Proceeding');
|
log.info('CallingClass.handleStartCall(): Proceeding');
|
||||||
|
|||||||
@@ -784,6 +784,25 @@ export function SmartPreferences(): React.JSX.Element | null {
|
|||||||
drop(itemStorage.put('cqsTestMode', value));
|
drop(itemStorage.put('cqsTestMode', value));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const setDredDuration = useCallback((value: number | undefined) => {
|
||||||
|
drop(itemStorage.put('dredDuration', value));
|
||||||
|
}, []);
|
||||||
|
const setIsDirectVp9Enabled = useCallback((value: boolean | undefined) => {
|
||||||
|
drop(itemStorage.put('isDirectVp9Enabled', value));
|
||||||
|
}, []);
|
||||||
|
const setDirectMaxBitrate = useCallback((value: number | undefined) => {
|
||||||
|
drop(itemStorage.put('directMaxBitrate', value));
|
||||||
|
}, []);
|
||||||
|
const setIsGroupVp9Enabled = useCallback((value: boolean | undefined) => {
|
||||||
|
drop(itemStorage.put('isGroupVp9Enabled', value));
|
||||||
|
}, []);
|
||||||
|
const setGroupMaxBitrate = useCallback((value: number | undefined) => {
|
||||||
|
drop(itemStorage.put('groupMaxBitrate', value));
|
||||||
|
}, []);
|
||||||
|
const setSfuUrl = useCallback((value: string | undefined) => {
|
||||||
|
drop(itemStorage.put('sfuUrl', value));
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (currentLocation.tab !== NavTab.Settings) {
|
if (currentLocation.tab !== NavTab.Settings) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -998,6 +1017,18 @@ export function SmartPreferences(): React.JSX.Element | null {
|
|||||||
}
|
}
|
||||||
cqsTestMode={cqsTestMode}
|
cqsTestMode={cqsTestMode}
|
||||||
setCqsTestMode={setCqsTestMode}
|
setCqsTestMode={setCqsTestMode}
|
||||||
|
dredDuration={items.dredDuration}
|
||||||
|
setDredDuration={setDredDuration}
|
||||||
|
setIsDirectVp9Enabled={setIsDirectVp9Enabled}
|
||||||
|
isDirectVp9Enabled={items.isDirectVp9Enabled}
|
||||||
|
setDirectMaxBitrate={setDirectMaxBitrate}
|
||||||
|
directMaxBitrate={items.directMaxBitrate}
|
||||||
|
setIsGroupVp9Enabled={setIsGroupVp9Enabled}
|
||||||
|
isGroupVp9Enabled={items.isGroupVp9Enabled}
|
||||||
|
setGroupMaxBitrate={setGroupMaxBitrate}
|
||||||
|
groupMaxBitrate={items.groupMaxBitrate}
|
||||||
|
sfuUrl={items.sfuUrl}
|
||||||
|
setSfuUrl={setSfuUrl}
|
||||||
/>
|
/>
|
||||||
</AxoProvider>
|
</AxoProvider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
|
|||||||
@@ -291,6 +291,14 @@ export type StorageAccessType = {
|
|||||||
defaultDimWallpaperInDarkMode: boolean;
|
defaultDimWallpaperInDarkMode: boolean;
|
||||||
defaultAutoBubbleColor: boolean;
|
defaultAutoBubbleColor: boolean;
|
||||||
|
|
||||||
|
// Used for manually controlling calling settings
|
||||||
|
dredDuration: number | undefined;
|
||||||
|
isDirectVp9Enabled: boolean | undefined;
|
||||||
|
directMaxBitrate: number | undefined;
|
||||||
|
isGroupVp9Enabled: boolean | undefined;
|
||||||
|
groupMaxBitrate: number | undefined;
|
||||||
|
sfuUrl: string | undefined;
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
'challenge:retry-message-ids': never;
|
'challenge:retry-message-ids': never;
|
||||||
nextSignedKeyRotationTime: number;
|
nextSignedKeyRotationTime: number;
|
||||||
@@ -514,6 +522,12 @@ const STORAGE_KEYS_TO_REMOVE_AFTER_UNLINK = [
|
|||||||
'backupMediaDownloadIdle',
|
'backupMediaDownloadIdle',
|
||||||
'callQualitySurveyCooldownDisabled',
|
'callQualitySurveyCooldownDisabled',
|
||||||
'localDeleteWarningShown',
|
'localDeleteWarningShown',
|
||||||
|
'dredDuration',
|
||||||
|
'directMaxBitrate',
|
||||||
|
'isDirectVp9Enabled',
|
||||||
|
'groupMaxBitrate',
|
||||||
|
'isGroupVp9Enabled',
|
||||||
|
'sfuUrl',
|
||||||
] as const satisfies ReadonlyArray<keyof StorageAccessType>;
|
] as const satisfies ReadonlyArray<keyof StorageAccessType>;
|
||||||
|
|
||||||
// Ensure every storage key is explicitly marked to be preserved or removed on unlink.
|
// Ensure every storage key is explicitly marked to be preserved or removed on unlink.
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ if (
|
|||||||
return message?.attributes;
|
return message?.attributes;
|
||||||
},
|
},
|
||||||
getReduxState: () => window.reduxStore.getState(),
|
getReduxState: () => window.reduxStore.getState(),
|
||||||
getSfuUrl: () => calling._sfuUrl,
|
getSfuUrl: () => calling.sfuUrl,
|
||||||
getIceServerOverride: () => calling._iceServerOverride,
|
getIceServerOverride: () => calling._iceServerOverride,
|
||||||
getSocketStatus: () => getSocketStatus(),
|
getSocketStatus: () => getSocketStatus(),
|
||||||
getStorageItem: (name: keyof StorageAccessType) => itemStorage.get(name),
|
getStorageItem: (name: keyof StorageAccessType) => itemStorage.get(name),
|
||||||
@@ -101,8 +101,8 @@ if (
|
|||||||
}
|
}
|
||||||
window.Flags[name] = value;
|
window.Flags[name] = value;
|
||||||
},
|
},
|
||||||
setSfuUrl: (url: string) => {
|
setSfuUrl: async (url: string) => {
|
||||||
calling._sfuUrl = url;
|
await itemStorage.put('sfuUrl', url);
|
||||||
},
|
},
|
||||||
setIceServerOverride: (
|
setIceServerOverride: (
|
||||||
override: GetIceServersResultType | string | undefined
|
override: GetIceServersResultType | string | undefined
|
||||||
|
|||||||
Reference in New Issue
Block a user