Calls: Fix private calls (#4121)
This commit is contained in:
parent
c3250df8d7
commit
449c241201
@ -167,8 +167,12 @@ export function encodePhoneCallData(params: ParamsOf<'encode'>): ReturnTypeOf<'e
|
|||||||
return currentPhoneCallState!.encode(...params);
|
return currentPhoneCallState!.encode(...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decodePhoneCallData(params: ParamsOf<'decode'>): ReturnTypeOf<'decode'> {
|
export async function decodePhoneCallData(params: ParamsOf<'decode'>) {
|
||||||
return currentPhoneCallState!.decode(...params);
|
if (!currentPhoneCallState) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const result = await currentPhoneCallState.decode(...params);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function confirmPhoneCall(params: ParamsOf<'confirmCall'>): ReturnTypeOf<'confirmCall'> {
|
export function confirmPhoneCall(params: ParamsOf<'confirmCall'>): ReturnTypeOf<'confirmCall'> {
|
||||||
|
|||||||
@ -90,6 +90,8 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
|||||||
...global,
|
...global,
|
||||||
phoneCall: call,
|
phoneCall: call,
|
||||||
};
|
};
|
||||||
|
setGlobal(global);
|
||||||
|
global = getGlobal();
|
||||||
|
|
||||||
if (phoneCall && phoneCall.id && call.id !== phoneCall.id) {
|
if (phoneCall && phoneCall.id && call.id !== phoneCall.id) {
|
||||||
if (call.state !== 'discarded') {
|
if (call.state !== 'discarded') {
|
||||||
|
|||||||
@ -148,7 +148,9 @@ export default (conference: Conference, isAnswer = false, isPresentation = false
|
|||||||
}
|
}
|
||||||
|
|
||||||
entry.sourceGroups.forEach((sourceGroup) => {
|
entry.sourceGroups.forEach((sourceGroup) => {
|
||||||
add(`a=ssrc-group:${sourceGroup.semantics} ${sourceGroup.sources.map(fromTelegramSource).join(' ')}`);
|
if (sourceGroup.semantics) {
|
||||||
|
add(`a=ssrc-group:${sourceGroup.semantics} ${sourceGroup.sources.map(fromTelegramSource).join(' ')}`);
|
||||||
|
}
|
||||||
sourceGroup.sources.forEach((ssrcTelegram) => {
|
sourceGroup.sources.forEach((ssrcTelegram) => {
|
||||||
const ssrc = fromTelegramSource(ssrcTelegram);
|
const ssrc = fromTelegramSource(ssrcTelegram);
|
||||||
add(`a=ssrc:${ssrc} cname:${entry.endpoint}`);
|
add(`a=ssrc:${ssrc} cname:${entry.endpoint}`);
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
p2pPayloadTypeToConference, removeRelatedAddress,
|
p2pPayloadTypeToConference, removeRelatedAddress,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import buildSdp, { Conference } from './buildSdp';
|
import buildSdp, { Conference } from './buildSdp';
|
||||||
import { getUserStreams, StreamType } from './secretsauce';
|
import { StreamType } from './secretsauce';
|
||||||
|
|
||||||
type P2pState = {
|
type P2pState = {
|
||||||
connection: RTCPeerConnection;
|
connection: RTCPeerConnection;
|
||||||
@ -18,7 +18,7 @@ type P2pState = {
|
|||||||
onUpdate: (...args: any[]) => void;
|
onUpdate: (...args: any[]) => void;
|
||||||
conference?: Partial<Conference>;
|
conference?: Partial<Conference>;
|
||||||
isOutgoing: boolean;
|
isOutgoing: boolean;
|
||||||
candidates: string[];
|
pendingCandidates: string[];
|
||||||
streams: {
|
streams: {
|
||||||
video?: MediaStream;
|
video?: MediaStream;
|
||||||
audio?: MediaStream;
|
audio?: MediaStream;
|
||||||
@ -59,7 +59,6 @@ function getUserStream(streamType: StreamType, facing: VideoFacingModeEnum = 'us
|
|||||||
|
|
||||||
return navigator.mediaDevices.getUserMedia({
|
return navigator.mediaDevices.getUserMedia({
|
||||||
audio: streamType === 'audio' ? {
|
audio: streamType === 'audio' ? {
|
||||||
// @ts-ignore
|
|
||||||
...(IS_ECHO_CANCELLATION_SUPPORTED && { echoCancellation: true }),
|
...(IS_ECHO_CANCELLATION_SUPPORTED && { echoCancellation: true }),
|
||||||
...(IS_NOISE_SUPPRESSION_SUPPORTED && { noiseSuppression: true }),
|
...(IS_NOISE_SUPPRESSION_SUPPORTED && { noiseSuppression: true }),
|
||||||
} : false,
|
} : false,
|
||||||
@ -164,8 +163,8 @@ export async function toggleStreamP2p(streamType: StreamType, value: boolean | u
|
|||||||
}
|
}
|
||||||
updateStreams();
|
updateStreams();
|
||||||
sendMediaState();
|
sendMediaState();
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,35 +182,24 @@ export async function joinPhoneCall(
|
|||||||
urls: [
|
urls: [
|
||||||
connection.isTurn && `turn:${connection.ip}:${connection.port}`,
|
connection.isTurn && `turn:${connection.ip}:${connection.port}`,
|
||||||
connection.isStun && `stun:${connection.ip}:${connection.port}`,
|
connection.isStun && `stun:${connection.ip}:${connection.port}`,
|
||||||
].filter(Boolean) as string[],
|
].filter(Boolean),
|
||||||
username: connection.username,
|
username: connection.username,
|
||||||
credentialType: 'password',
|
credentialType: 'password',
|
||||||
credential: connection.password,
|
credential: connection.password,
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
iceCandidatePoolSize: 2,
|
iceTransportPolicy: isP2p ? 'all' : 'relay',
|
||||||
|
bundlePolicy: 'max-bundle'
|
||||||
});
|
});
|
||||||
const slnc = silence(new AudioContext());
|
|
||||||
const video = black({ width: 640, height: 480 });
|
|
||||||
const screenshare = black({ width: 640, height: 480 });
|
|
||||||
conn.addTrack(slnc.getTracks()[0], slnc);
|
|
||||||
conn.addTrack(video.getTracks()[0], video);
|
|
||||||
conn.addTrack(screenshare.getTracks()[0], screenshare);
|
|
||||||
|
|
||||||
conn.onicecandidate = (e) => {
|
conn.onicecandidate = (e) => {
|
||||||
if (!e.candidate) return;
|
if (!e.candidate) {
|
||||||
|
|
||||||
const { candidate } = e.candidate;
|
|
||||||
if(!isP2p && !isRelayAddress(candidate)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
const candidateWithoutRelatedAddress = !isP2p ? removeRelatedAddress(candidate) : candidate;
|
|
||||||
|
|
||||||
emitSignalingData({
|
emitSignalingData({
|
||||||
'@type': 'Candidates',
|
'@type': 'Candidates',
|
||||||
candidates: [{
|
candidates: [{
|
||||||
sdpString: candidateWithoutRelatedAddress,
|
sdpString: e.candidate.candidate,
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -240,6 +228,29 @@ export async function joinPhoneCall(
|
|||||||
updateStreams();
|
updateStreams();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn.oniceconnectionstatechange = async (e) => {
|
||||||
|
switch(conn.iceConnectionState) {
|
||||||
|
case 'disconnected':
|
||||||
|
case 'failed':
|
||||||
|
if (isOutgoing) {
|
||||||
|
await createOffer(conn, {
|
||||||
|
offerToReceiveAudio: true,
|
||||||
|
offerToReceiveVideo: true,
|
||||||
|
iceRestart: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const slnc = silence(new AudioContext());
|
||||||
|
const video = black({ width: 640, height: 480 });
|
||||||
|
const screenshare = black({ width: 640, height: 480 });
|
||||||
|
conn.addTrack(slnc.getTracks()[0], slnc);
|
||||||
|
conn.addTrack(video.getTracks()[0], video);
|
||||||
|
conn.addTrack(screenshare.getTracks()[0], screenshare);
|
||||||
|
|
||||||
const dc = conn.createDataChannel('data', {
|
const dc = conn.createDataChannel('data', {
|
||||||
id: 0,
|
id: 0,
|
||||||
negotiated: true,
|
negotiated: true,
|
||||||
@ -256,7 +267,7 @@ export async function joinPhoneCall(
|
|||||||
connection: conn,
|
connection: conn,
|
||||||
emitSignalingData,
|
emitSignalingData,
|
||||||
isOutgoing,
|
isOutgoing,
|
||||||
candidates: [],
|
pendingCandidates: [],
|
||||||
onUpdate,
|
onUpdate,
|
||||||
streams: {
|
streams: {
|
||||||
ownVideo: video,
|
ownVideo: video,
|
||||||
@ -281,19 +292,15 @@ export async function joinPhoneCall(
|
|||||||
toggleStreamP2p('video', true);
|
toggleStreamP2p('video', true);
|
||||||
}
|
}
|
||||||
toggleStreamP2p('audio', true);
|
toggleStreamP2p('audio', true);
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOutgoing) {
|
if (isOutgoing) {
|
||||||
const offer = await conn.createOffer({
|
await createOffer(conn, {
|
||||||
offerToReceiveAudio: true,
|
offerToReceiveAudio: true,
|
||||||
offerToReceiveVideo: true,
|
offerToReceiveVideo: true,
|
||||||
});
|
})
|
||||||
|
|
||||||
await conn.setLocalDescription(offer);
|
|
||||||
|
|
||||||
sendInitialSetup(parseSdp(offer, true) as P2pParsedSdp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,8 +382,6 @@ function sendInitialSetup(sdp: P2pParsedSdp) {
|
|||||||
export async function processSignalingMessage(message: P2pMessage) {
|
export async function processSignalingMessage(message: P2pMessage) {
|
||||||
if (!state || !state.connection) return;
|
if (!state || !state.connection) return;
|
||||||
|
|
||||||
console.log(message);
|
|
||||||
|
|
||||||
switch (message['@type']) {
|
switch (message['@type']) {
|
||||||
case 'MediaState': {
|
case 'MediaState': {
|
||||||
state.mediaState = message;
|
state.mediaState = message;
|
||||||
@ -385,21 +390,13 @@ export async function processSignalingMessage(message: P2pMessage) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'Candidates': {
|
case 'Candidates': {
|
||||||
const { candidates, gotInitialSetup } = state;
|
const { pendingCandidates, gotInitialSetup } = state;
|
||||||
|
|
||||||
if (!candidates) return;
|
|
||||||
|
|
||||||
message.candidates.forEach((candidate) => {
|
message.candidates.forEach((candidate) => {
|
||||||
state!.candidates.push(candidate.sdpString);
|
pendingCandidates.push(candidate.sdpString);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (gotInitialSetup) {
|
if (gotInitialSetup) {
|
||||||
await Promise.all(state.candidates.map((c) => state!.connection.addIceCandidate({
|
await commitPendingIceCandidates();
|
||||||
candidate: c,
|
|
||||||
sdpMLineIndex: 0,
|
|
||||||
})));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'InitialSetup': {
|
case 'InitialSetup': {
|
||||||
@ -426,7 +423,6 @@ export async function processSignalingMessage(message: P2pMessage) {
|
|||||||
endpoint: '0',
|
endpoint: '0',
|
||||||
mid: '0',
|
mid: '0',
|
||||||
sourceGroups: [{
|
sourceGroups: [{
|
||||||
semantics: 'FID',
|
|
||||||
sources: [message.audio.ssrc],
|
sources: [message.audio.ssrc],
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
@ -471,19 +467,41 @@ export async function processSignalingMessage(message: P2pMessage) {
|
|||||||
if (!isOutgoing) {
|
if (!isOutgoing) {
|
||||||
const answer = await connection.createAnswer();
|
const answer = await connection.createAnswer();
|
||||||
if (!answer) return;
|
if (!answer) return;
|
||||||
|
|
||||||
await connection.setLocalDescription(answer);
|
await connection.setLocalDescription(answer);
|
||||||
|
|
||||||
sendInitialSetup(parseSdp(answer, true) as P2pParsedSdp);
|
sendInitialSetup(parseSdp(answer, true) as P2pParsedSdp);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.gotInitialSetup = true;
|
state.gotInitialSetup = true;
|
||||||
await Promise.all(state.candidates.map((c) => connection.addIceCandidate({
|
await commitPendingIceCandidates();
|
||||||
candidate: c,
|
|
||||||
sdpMLineIndex: 0,
|
|
||||||
})));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function commitPendingIceCandidates() {
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { pendingCandidates, connection } = state;
|
||||||
|
if (!pendingCandidates.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await Promise.all(pendingCandidates.map((c) => tryAddCandidate(connection, c)));
|
||||||
|
state.pendingCandidates = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function tryAddCandidate(connection: RTCPeerConnection, candidate: string) {
|
||||||
|
try {
|
||||||
|
await connection.addIceCandidate({
|
||||||
|
candidate,
|
||||||
|
sdpMLineIndex: 0,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createOffer(pc: RTCPeerConnection, params: RTCOfferOptions) {
|
||||||
|
const offer = await pc.createOffer(params);
|
||||||
|
sendInitialSetup(parseSdp(offer, true) as P2pParsedSdp);
|
||||||
|
await pc.setLocalDescription(offer);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user