Group calling SFU URL should be configurable
This commit is contained in:
parent
ec35bdc3e5
commit
23fed9ce63
6 changed files with 87 additions and 75 deletions
|
@ -11,6 +11,7 @@
|
||||||
"contentProxyUrl": "http://contentproxy.signal.org:443",
|
"contentProxyUrl": "http://contentproxy.signal.org:443",
|
||||||
"updatesUrl": "https://updates2.signal.org/desktop",
|
"updatesUrl": "https://updates2.signal.org/desktop",
|
||||||
"updatesPublicKey": "fd7dd3de7149dc0a127909fee7de0f7620ddd0de061b37a2c303e37de802a401",
|
"updatesPublicKey": "fd7dd3de7149dc0a127909fee7de0f7620ddd0de061b37a2c303e37de802a401",
|
||||||
|
"sfuUrl": "https://sfu.voip.signal.org/",
|
||||||
"updatesEnabled": false,
|
"updatesEnabled": false,
|
||||||
"openDevTools": false,
|
"openDevTools": false,
|
||||||
"buildExpiration": 0,
|
"buildExpiration": 0,
|
||||||
|
|
1
main.js
1
main.js
|
@ -204,6 +204,7 @@ function prepareURL(pathSegments, moreKeys) {
|
||||||
appInstance: process.env.NODE_APP_INSTANCE,
|
appInstance: process.env.NODE_APP_INSTANCE,
|
||||||
proxyUrl: process.env.HTTPS_PROXY || process.env.https_proxy,
|
proxyUrl: process.env.HTTPS_PROXY || process.env.https_proxy,
|
||||||
contentProxyUrl: config.contentProxyUrl,
|
contentProxyUrl: config.contentProxyUrl,
|
||||||
|
sfuUrl: config.get('sfuUrl'),
|
||||||
importMode: importMode ? true : undefined, // for stringify()
|
importMode: importMode ? true : undefined, // for stringify()
|
||||||
serverPublicParams: config.get('serverPublicParams'),
|
serverPublicParams: config.get('serverPublicParams'),
|
||||||
serverTrustRoot: config.get('serverTrustRoot'),
|
serverTrustRoot: config.get('serverTrustRoot'),
|
||||||
|
|
|
@ -45,6 +45,7 @@ try {
|
||||||
window.getHostName = () => config.hostname;
|
window.getHostName = () => config.hostname;
|
||||||
window.getServerTrustRoot = () => config.serverTrustRoot;
|
window.getServerTrustRoot = () => config.serverTrustRoot;
|
||||||
window.getServerPublicParams = () => config.serverPublicParams;
|
window.getServerPublicParams = () => config.serverPublicParams;
|
||||||
|
window.getSfuUrl = () => config.sfuUrl;
|
||||||
window.isBehindProxy = () => Boolean(config.proxyUrl);
|
window.isBehindProxy = () => Boolean(config.proxyUrl);
|
||||||
|
|
||||||
function setSystemTheme() {
|
function setSystemTheme() {
|
||||||
|
|
|
@ -646,7 +646,10 @@ type WhatIsThis = import('./window.d').WhatIsThis;
|
||||||
window.reduxActions.updates,
|
window.reduxActions.updates,
|
||||||
window.Whisper.events
|
window.Whisper.events
|
||||||
);
|
);
|
||||||
window.Signal.Services.calling.initialize(window.reduxActions.calling);
|
window.Signal.Services.calling.initialize(
|
||||||
|
window.reduxActions.calling,
|
||||||
|
window.getSfuUrl()
|
||||||
|
);
|
||||||
window.reduxActions.expiration.hydrateExpirationStatus(
|
window.reduxActions.expiration.hydrateExpirationStatus(
|
||||||
window.Signal.Util.hasExpired()
|
window.Signal.Util.hasExpired()
|
||||||
);
|
);
|
||||||
|
|
|
@ -55,8 +55,6 @@ import { fetchMembershipProof, getMembershipList } from '../groups';
|
||||||
import { missingCaseError } from '../util/missingCaseError';
|
import { missingCaseError } from '../util/missingCaseError';
|
||||||
import { normalizeGroupCallTimestamp } from '../util/ringrtc/normalizeGroupCallTimestamp';
|
import { normalizeGroupCallTimestamp } from '../util/ringrtc/normalizeGroupCallTimestamp';
|
||||||
|
|
||||||
const RINGRTC_SFU_URL = 'https://sfu.voip.signal.org/';
|
|
||||||
|
|
||||||
const RINGRTC_HTTP_METHOD_TO_OUR_HTTP_METHOD: Map<
|
const RINGRTC_HTTP_METHOD_TO_OUR_HTTP_METHOD: Map<
|
||||||
HttpMethod,
|
HttpMethod,
|
||||||
'GET' | 'PUT' | 'POST' | 'DELETE'
|
'GET' | 'PUT' | 'POST' | 'DELETE'
|
||||||
|
@ -92,6 +90,8 @@ export class CallingClass {
|
||||||
|
|
||||||
private uxActions?: UxActionsType;
|
private uxActions?: UxActionsType;
|
||||||
|
|
||||||
|
private sfuUrl?: string;
|
||||||
|
|
||||||
private lastMediaDeviceSettings?: MediaDeviceSettings;
|
private lastMediaDeviceSettings?: MediaDeviceSettings;
|
||||||
|
|
||||||
private deviceReselectionTimer?: NodeJS.Timeout;
|
private deviceReselectionTimer?: NodeJS.Timeout;
|
||||||
|
@ -105,11 +105,14 @@ export class CallingClass {
|
||||||
this.callsByConversation = {};
|
this.callsByConversation = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(uxActions: UxActionsType): void {
|
initialize(uxActions: UxActionsType, sfuUrl: string): void {
|
||||||
this.uxActions = uxActions;
|
this.uxActions = uxActions;
|
||||||
if (!uxActions) {
|
if (!uxActions) {
|
||||||
throw new Error('CallingClass.initialize: Invalid uxActions.');
|
throw new Error('CallingClass.initialize: Invalid uxActions.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.sfuUrl = sfuUrl;
|
||||||
|
|
||||||
RingRTC.handleOutgoingSignaling = this.handleOutgoingSignaling.bind(this);
|
RingRTC.handleOutgoingSignaling = this.handleOutgoingSignaling.bind(this);
|
||||||
RingRTC.handleIncomingCall = this.handleIncomingCall.bind(this);
|
RingRTC.handleIncomingCall = this.handleIncomingCall.bind(this);
|
||||||
RingRTC.handleAutoEndedIncomingCallRequest = this.handleAutoEndedIncomingCallRequest.bind(
|
RingRTC.handleAutoEndedIncomingCallRequest = this.handleAutoEndedIncomingCallRequest.bind(
|
||||||
|
@ -333,6 +336,10 @@ export class CallingClass {
|
||||||
return statefulPeekInfo;
|
return statefulPeekInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.sfuUrl) {
|
||||||
|
throw new Error('Missing SFU URL; not peeking group call');
|
||||||
|
}
|
||||||
|
|
||||||
const conversation = window.ConversationController.get(conversationId);
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
throw new Error('Missing conversation; not peeking group call');
|
throw new Error('Missing conversation; not peeking group call');
|
||||||
|
@ -352,7 +359,7 @@ export class CallingClass {
|
||||||
const membershipProof = new TextEncoder().encode(proof).buffer;
|
const membershipProof = new TextEncoder().encode(proof).buffer;
|
||||||
|
|
||||||
return RingRTC.peekGroupCall(
|
return RingRTC.peekGroupCall(
|
||||||
RINGRTC_SFU_URL,
|
this.sfuUrl,
|
||||||
membershipProof,
|
membershipProof,
|
||||||
this.getGroupCallMembers(conversationId)
|
this.getGroupCallMembers(conversationId)
|
||||||
);
|
);
|
||||||
|
@ -388,90 +395,88 @@ export class CallingClass {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.sfuUrl) {
|
||||||
|
throw new Error('Missing SFU URL; not connecting group call');
|
||||||
|
}
|
||||||
|
|
||||||
const groupIdBuffer = base64ToArrayBuffer(groupId);
|
const groupIdBuffer = base64ToArrayBuffer(groupId);
|
||||||
|
|
||||||
let updateMessageState = GroupCallUpdateMessageState.SentNothing;
|
let updateMessageState = GroupCallUpdateMessageState.SentNothing;
|
||||||
let isRequestingMembershipProof = false;
|
let isRequestingMembershipProof = false;
|
||||||
|
|
||||||
const outerGroupCall = RingRTC.getGroupCall(
|
const outerGroupCall = RingRTC.getGroupCall(groupIdBuffer, this.sfuUrl, {
|
||||||
groupIdBuffer,
|
onLocalDeviceStateChanged: groupCall => {
|
||||||
RINGRTC_SFU_URL,
|
const localDeviceState = groupCall.getLocalDeviceState();
|
||||||
{
|
const { eraId } = groupCall.getPeekInfo() || {};
|
||||||
onLocalDeviceStateChanged: groupCall => {
|
|
||||||
const localDeviceState = groupCall.getLocalDeviceState();
|
if (localDeviceState.connectionState === ConnectionState.NotConnected) {
|
||||||
const { eraId } = groupCall.getPeekInfo() || {};
|
// NOTE: This assumes that only one call is active at a time. For example, if
|
||||||
|
// there are two calls using the camera, this will disable both of them.
|
||||||
|
// That's fine for now, but this will break if that assumption changes.
|
||||||
|
this.disableLocalCamera();
|
||||||
|
|
||||||
|
delete this.callsByConversation[conversationId];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
localDeviceState.connectionState === ConnectionState.NotConnected
|
updateMessageState === GroupCallUpdateMessageState.SentJoin &&
|
||||||
|
eraId
|
||||||
) {
|
) {
|
||||||
// NOTE: This assumes that only one call is active at a time. For example, if
|
updateMessageState = GroupCallUpdateMessageState.SentLeft;
|
||||||
// there are two calls using the camera, this will disable both of them.
|
this.sendGroupCallUpdateMessage(conversationId, eraId);
|
||||||
// That's fine for now, but this will break if that assumption changes.
|
}
|
||||||
|
} else {
|
||||||
|
this.callsByConversation[conversationId] = groupCall;
|
||||||
|
|
||||||
|
// NOTE: This assumes only one active call at a time. See comment above.
|
||||||
|
if (localDeviceState.videoMuted) {
|
||||||
this.disableLocalCamera();
|
this.disableLocalCamera();
|
||||||
|
|
||||||
delete this.callsByConversation[conversationId];
|
|
||||||
|
|
||||||
if (
|
|
||||||
updateMessageState === GroupCallUpdateMessageState.SentJoin &&
|
|
||||||
eraId
|
|
||||||
) {
|
|
||||||
updateMessageState = GroupCallUpdateMessageState.SentLeft;
|
|
||||||
this.sendGroupCallUpdateMessage(conversationId, eraId);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.callsByConversation[conversationId] = groupCall;
|
this.videoCapturer.enableCaptureAndSend(groupCall);
|
||||||
|
|
||||||
// NOTE: This assumes only one active call at a time. See comment above.
|
|
||||||
if (localDeviceState.videoMuted) {
|
|
||||||
this.disableLocalCamera();
|
|
||||||
} else {
|
|
||||||
this.videoCapturer.enableCaptureAndSend(groupCall);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
updateMessageState === GroupCallUpdateMessageState.SentNothing &&
|
|
||||||
localDeviceState.joinState === JoinState.Joined &&
|
|
||||||
eraId
|
|
||||||
) {
|
|
||||||
updateMessageState = GroupCallUpdateMessageState.SentJoin;
|
|
||||||
this.sendGroupCallUpdateMessage(conversationId, eraId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.syncGroupCallToRedux(conversationId, groupCall);
|
if (
|
||||||
},
|
updateMessageState === GroupCallUpdateMessageState.SentNothing &&
|
||||||
onRemoteDeviceStatesChanged: groupCall => {
|
localDeviceState.joinState === JoinState.Joined &&
|
||||||
this.syncGroupCallToRedux(conversationId, groupCall);
|
eraId
|
||||||
},
|
) {
|
||||||
onPeekChanged: groupCall => {
|
updateMessageState = GroupCallUpdateMessageState.SentJoin;
|
||||||
this.syncGroupCallToRedux(conversationId, groupCall);
|
this.sendGroupCallUpdateMessage(conversationId, eraId);
|
||||||
},
|
|
||||||
async requestMembershipProof(groupCall) {
|
|
||||||
if (isRequestingMembershipProof) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
isRequestingMembershipProof = true;
|
}
|
||||||
try {
|
|
||||||
const proof = await fetchMembershipProof({
|
this.syncGroupCallToRedux(conversationId, groupCall);
|
||||||
publicParams,
|
},
|
||||||
secretParams,
|
onRemoteDeviceStatesChanged: groupCall => {
|
||||||
});
|
this.syncGroupCallToRedux(conversationId, groupCall);
|
||||||
if (proof) {
|
},
|
||||||
const proofArray = new TextEncoder().encode(proof);
|
onPeekChanged: groupCall => {
|
||||||
groupCall.setMembershipProof(proofArray.buffer);
|
this.syncGroupCallToRedux(conversationId, groupCall);
|
||||||
}
|
},
|
||||||
} catch (err) {
|
async requestMembershipProof(groupCall) {
|
||||||
window.log.error('Failed to fetch membership proof', err);
|
if (isRequestingMembershipProof) {
|
||||||
} finally {
|
return;
|
||||||
isRequestingMembershipProof = false;
|
}
|
||||||
|
isRequestingMembershipProof = true;
|
||||||
|
try {
|
||||||
|
const proof = await fetchMembershipProof({
|
||||||
|
publicParams,
|
||||||
|
secretParams,
|
||||||
|
});
|
||||||
|
if (proof) {
|
||||||
|
const proofArray = new TextEncoder().encode(proof);
|
||||||
|
groupCall.setMembershipProof(proofArray.buffer);
|
||||||
}
|
}
|
||||||
},
|
} catch (err) {
|
||||||
requestGroupMembers: groupCall => {
|
window.log.error('Failed to fetch membership proof', err);
|
||||||
groupCall.setGroupMembers(this.getGroupCallMembers(conversationId));
|
} finally {
|
||||||
},
|
isRequestingMembershipProof = false;
|
||||||
onEnded: noop,
|
}
|
||||||
}
|
},
|
||||||
);
|
requestGroupMembers: groupCall => {
|
||||||
|
groupCall.setGroupMembers(this.getGroupCallMembers(conversationId));
|
||||||
|
},
|
||||||
|
onEnded: noop,
|
||||||
|
});
|
||||||
|
|
||||||
if (!outerGroupCall) {
|
if (!outerGroupCall) {
|
||||||
// This should be very rare, likely due to RingRTC not being able to get a lock
|
// This should be very rare, likely due to RingRTC not being able to get a lock
|
||||||
|
|
1
ts/window.d.ts
vendored
1
ts/window.d.ts
vendored
|
@ -114,6 +114,7 @@ declare global {
|
||||||
getMediaCameraPermissions: () => Promise<boolean>;
|
getMediaCameraPermissions: () => Promise<boolean>;
|
||||||
getMediaPermissions: () => Promise<boolean>;
|
getMediaPermissions: () => Promise<boolean>;
|
||||||
getServerPublicParams: () => string;
|
getServerPublicParams: () => string;
|
||||||
|
getSfuUrl: () => string;
|
||||||
getSocketStatus: () => number;
|
getSocketStatus: () => number;
|
||||||
getSyncRequest: () => WhatIsThis;
|
getSyncRequest: () => WhatIsThis;
|
||||||
getTitle: () => string;
|
getTitle: () => string;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue