mirror of
https://github.com/irislib/iris-messenger.git
synced 2024-09-19 17:46:33 +00:00
remove VideoCall and its mp3s, 5 sec timeout to NetworkFirst cache
This commit is contained in:
parent
69c9f38feb
commit
8a8ac6718f
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -8,7 +8,6 @@ import '@fontsource/lato';
|
||||
import Footer from './components/Footer';
|
||||
import MediaPlayer from './components/MediaPlayer';
|
||||
import Menu from './components/Menu';
|
||||
import VideoCall from './components/VideoCall';
|
||||
import { translationLoaded } from './translations/Translation';
|
||||
import About from './views/About';
|
||||
import Chat from './views/chat/Chat';
|
||||
@ -193,7 +192,6 @@ class Main extends Component<Props, ReactState> {
|
||||
</section>
|
||||
<MediaPlayer />
|
||||
<Footer />
|
||||
<VideoCall />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,439 +0,0 @@
|
||||
import { html } from 'htm/preact';
|
||||
import iris from 'iris-lib';
|
||||
import $ from 'jquery';
|
||||
import noop from 'lodash/noop';
|
||||
import { Component } from 'preact';
|
||||
import { route } from 'preact-router';
|
||||
|
||||
import { translate as t } from '../translations/Translation';
|
||||
|
||||
import Button from './basic/Button';
|
||||
|
||||
const ringSound = new Audio('../../assets/audio/ring.mp3');
|
||||
ringSound.loop = true;
|
||||
const callSound = new Audio('../../assets/audio/call.mp3');
|
||||
let callTimeout;
|
||||
let callSoundTimeout;
|
||||
let callingInterval;
|
||||
let incomingCallNotification;
|
||||
let userMediaStream;
|
||||
let ourIceCandidates;
|
||||
|
||||
let localStorageIce = localStorage.getItem('rtcConfig');
|
||||
let DEFAULT_RTC_CONFIG = {
|
||||
iceServers: [{ urls: ['stun:turn.hepic.tel'] }, { urls: ['stun:stun.l.google.com:19302'] }],
|
||||
};
|
||||
let RTC_CONFIG = localStorageIce ? JSON.parse(localStorageIce) : DEFAULT_RTC_CONFIG;
|
||||
|
||||
function getRTCConfig() {
|
||||
return RTC_CONFIG;
|
||||
}
|
||||
|
||||
function setRTCConfig(c) {
|
||||
RTC_CONFIG = c;
|
||||
try {
|
||||
localStorage.setItem('rtcConfig', JSON.stringify(RTC_CONFIG));
|
||||
} catch (e) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
class VideoCall extends Component {
|
||||
componentDidMount() {
|
||||
iris.local().get('activeCall').put(null);
|
||||
iris.local().get('outgoingCall').put(null);
|
||||
iris.local().get('incomingCall').put(null);
|
||||
/*iris.local().get('call').open(call => {
|
||||
this.onCallMessage(call.pub, call.call);
|
||||
});*/
|
||||
iris
|
||||
.local()
|
||||
.get('incomingCall')
|
||||
.on((incomingCall) => {
|
||||
if (!incomingCall) {
|
||||
clearTimeout(callTimeout);
|
||||
ringSound.pause();
|
||||
ringSound.currentTime = 0;
|
||||
incomingCallNotification && incomingCallNotification.close();
|
||||
} else {
|
||||
if (this.state.activeCall) return;
|
||||
ringSound.play().catch(noop);
|
||||
this.notifyIfNotVisible(incomingCall, t('incoming_call'));
|
||||
}
|
||||
this.setState({ incomingCall });
|
||||
});
|
||||
iris
|
||||
.local()
|
||||
.get('activeCall')
|
||||
.on((activeCall) => {
|
||||
this.setState({ activeCall });
|
||||
this.stopCalling();
|
||||
});
|
||||
iris
|
||||
.local()
|
||||
.get('outgoingCall')
|
||||
.on((outgoingCall) => {
|
||||
outgoingCall && this.onCallUser(outgoingCall);
|
||||
this.setState({ outgoingCall });
|
||||
});
|
||||
}
|
||||
|
||||
async answerCall(pub) {
|
||||
iris.local().get('incomingCall').put(null);
|
||||
iris.local().get('activeCall').put(pub);
|
||||
await this.initConnection(false, pub);
|
||||
}
|
||||
|
||||
onCallMessage(pub, call) {
|
||||
this.stopCalling();
|
||||
if (call && call !== 'null' && call.time) {
|
||||
let d = new Date(call.time);
|
||||
if (new Date() - d > 5000) {
|
||||
console.log('ignoring old call from', pub);
|
||||
return;
|
||||
}
|
||||
if (call.offer) {
|
||||
if (iris.private(pub).rejectedTime && new Date() - iris.private(pub).rejectedTime < 5000) {
|
||||
this.rejectCall(pub);
|
||||
return;
|
||||
}
|
||||
iris.local().get('incomingCall').put(pub);
|
||||
clearTimeout(callTimeout);
|
||||
callTimeout = setTimeout(() => iris.local().get('incomingCall').put(null), 5000);
|
||||
}
|
||||
} else {
|
||||
this.callClosed(pub);
|
||||
}
|
||||
}
|
||||
|
||||
notifyIfNotVisible(pub, text) {
|
||||
if (document.visibilityState !== 'visible') {
|
||||
incomingCallNotification = new Notification(iris.private(pub).name, {
|
||||
icon: '/assets/img/icon128.png',
|
||||
body: text,
|
||||
requireInteraction: true,
|
||||
silent: true,
|
||||
});
|
||||
incomingCallNotification.onclick = function () {
|
||||
route(`/chat/${pub}`);
|
||||
window.focus();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
resetCalls() {
|
||||
iris.local().get('outgoingCall').put(null);
|
||||
iris.local().get('activeCall').put(null);
|
||||
iris.local().get('incomingCall').put(null);
|
||||
}
|
||||
|
||||
callClosed(pub) {
|
||||
this.stopCalling(pub);
|
||||
this.resetCalls();
|
||||
if (this.state.outgoingCall) {
|
||||
this.stopUserMedia(pub);
|
||||
this.notifyIfNotVisible(t('call_rejected'));
|
||||
} else if (this.state.activeCall) {
|
||||
this.stopUserMedia(pub);
|
||||
iris.private(pub).put('call', 'null');
|
||||
this.notifyIfNotVisible(t('call_ended'));
|
||||
}
|
||||
if (iris.private(pub)) {
|
||||
iris.private(pub).pc && iris.private(pub).pc.close();
|
||||
iris.private(pub).pc = null;
|
||||
}
|
||||
}
|
||||
|
||||
async addStreamToPeerConnection(pc) {
|
||||
let constraints = {
|
||||
audio: true,
|
||||
video: true,
|
||||
};
|
||||
userMediaStream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
userMediaStream.getTracks().forEach((track) => {
|
||||
pc.addTrack(track, userMediaStream);
|
||||
});
|
||||
const localVideo = $('#localvideo');
|
||||
localVideo[0].srcObject = userMediaStream;
|
||||
localVideo[0].onloadedmetadata = function () {
|
||||
localVideo[0].muted = true;
|
||||
localVideo[0].play();
|
||||
};
|
||||
localVideo.attr('disabled', true);
|
||||
}
|
||||
|
||||
timeoutPlayCallSound() {
|
||||
callSoundTimeout = setTimeout(() => callSound.play(), 3500);
|
||||
}
|
||||
|
||||
async onCallUser(pub, video = true) {
|
||||
if (this.state.outgoingCall) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.initConnection(true, pub);
|
||||
console.log('calling', pub);
|
||||
let call = () =>
|
||||
iris.private(pub).put('call', {
|
||||
time: new Date().toISOString(),
|
||||
type: video ? 'video' : 'voice',
|
||||
offer: true,
|
||||
});
|
||||
callingInterval = setInterval(call, 1000);
|
||||
call();
|
||||
callSound.addEventListener('ended', () => this.timeoutPlayCallSound());
|
||||
callSound.play();
|
||||
iris.local().get('outgoingCall').put(pub);
|
||||
}
|
||||
|
||||
cancelCall(pub) {
|
||||
iris.local().get('outgoingCall').put(null);
|
||||
this.stopCalling();
|
||||
this.stopUserMedia(pub);
|
||||
iris.private(pub).put('call', 'null');
|
||||
iris.private(pub).pc && iris.private(pub).pc.close();
|
||||
iris.private(pub).pc = null;
|
||||
}
|
||||
|
||||
stopUserMedia() {
|
||||
userMediaStream.getTracks().forEach((track) => track.stop());
|
||||
}
|
||||
|
||||
stopCalling() {
|
||||
iris.local().get('outgoingCall').put(null);
|
||||
callSound.pause();
|
||||
callSound.removeEventListener('ended', () => this.timeoutPlayCallSound());
|
||||
clearTimeout(callSoundTimeout);
|
||||
callSound.currentTime = 0;
|
||||
clearInterval(callingInterval);
|
||||
callingInterval = null;
|
||||
}
|
||||
|
||||
endCall(pub) {
|
||||
iris.private(pub).pc && iris.private(pub).pc.close();
|
||||
this.stopUserMedia(pub);
|
||||
iris.private(pub).put('call', 'null');
|
||||
iris.private(pub).pc = null;
|
||||
iris.local().get('activeCall').put(null);
|
||||
}
|
||||
|
||||
rejectCall(pub) {
|
||||
iris.private(pub).rejectedTime = new Date();
|
||||
iris.local().get('incomingCall').put(null);
|
||||
console.log('rejectCall', pub, iris.private(pub));
|
||||
iris.private(pub).put('call', 'null');
|
||||
}
|
||||
|
||||
async initConnection(createOffer, pub) {
|
||||
console.log('initConnection', createOffer, pub);
|
||||
ourIceCandidates = {};
|
||||
const theirIceCandidateKeys = [];
|
||||
const chat = iris.private(pub);
|
||||
chat.pc = new RTCPeerConnection(RTC_CONFIG);
|
||||
console.log(chat.pc.signalingState);
|
||||
await this.addStreamToPeerConnection(chat.pc);
|
||||
async function createOfferFn() {
|
||||
try {
|
||||
if (chat.isNegotiating) {
|
||||
return;
|
||||
}
|
||||
chat.isNegotiating = true;
|
||||
let offer = await chat.pc.createOffer();
|
||||
chat.pc.setLocalDescription(offer);
|
||||
console.log('sending our sdp', offer);
|
||||
chat.put('sdp', { time: new Date().toISOString(), data: offer });
|
||||
} finally {
|
||||
chat.isNegotiating = false;
|
||||
}
|
||||
}
|
||||
if (createOffer) {
|
||||
await createOfferFn();
|
||||
}
|
||||
chat.onTheir('sdp', async (sdp) => {
|
||||
console.log('got their sdp', sdp);
|
||||
if (!chat.pc) {
|
||||
console.log(1);
|
||||
return;
|
||||
}
|
||||
if (createOffer && chat.pc.signalingState === 'stable') {
|
||||
console.log(2);
|
||||
return;
|
||||
}
|
||||
if (sdp.data && sdp.time && new Date(sdp.time).getTime() < new Date() - 5000) {
|
||||
console.log(3);
|
||||
return;
|
||||
}
|
||||
chat.pc.setRemoteDescription(new RTCSessionDescription(sdp.data));
|
||||
console.log(4);
|
||||
});
|
||||
chat.onTheir('icecandidates', (c) => {
|
||||
console.log('got their icecandidates', c);
|
||||
if (!chat.pc || chat.pc.signalingState === 'closed') {
|
||||
return;
|
||||
}
|
||||
if (c.data && c.time && new Date(c.time).getTime() < new Date() - 5000) {
|
||||
return;
|
||||
}
|
||||
Object.keys(c.data).forEach((k) => {
|
||||
if (theirIceCandidateKeys.indexOf(k) === -1) {
|
||||
theirIceCandidateKeys.push(k);
|
||||
chat.pc.addIceCandidate(new RTCIceCandidate(c.data[k])).then(console.log, console.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
chat.pc.onicecandidate =
|
||||
chat.pc.onicecandidate ||
|
||||
(({ candidate }) => {
|
||||
if (!candidate) return;
|
||||
console.log('sending our ice candidate');
|
||||
let i = btoa(Math.random().toString()).slice(0, 12);
|
||||
ourIceCandidates[i] = candidate;
|
||||
chat.put('icecandidates', {
|
||||
time: new Date().toISOString(),
|
||||
data: ourIceCandidates,
|
||||
});
|
||||
});
|
||||
if (createOffer) {
|
||||
chat.pc.onnegotiationneeded = async () => {
|
||||
createOfferFn();
|
||||
};
|
||||
}
|
||||
chat.pc.onsignalingstatechange = async () => {
|
||||
if (!chat.pc) {
|
||||
return;
|
||||
}
|
||||
console.log(`Signaling State Change:${chat.pc}`, chat.pc.signalingState);
|
||||
switch (chat.pc.signalingState) {
|
||||
case 'have-remote-offer': {
|
||||
const answer = await chat.pc.createAnswer({
|
||||
offerToReceiveAudio: 1,
|
||||
offerToReceiveVideo: 1,
|
||||
});
|
||||
chat.pc.setLocalDescription(answer);
|
||||
chat.put('sdp', { time: new Date().toISOString(), data: answer });
|
||||
break;
|
||||
}
|
||||
case 'stable':
|
||||
this.stopCalling();
|
||||
console.log('call answered by', pub);
|
||||
iris.local().get('activeCall').put(pub);
|
||||
break;
|
||||
case 'closed':
|
||||
console.log("Signalling state is 'closed'");
|
||||
this.callClosed(pub);
|
||||
break;
|
||||
}
|
||||
};
|
||||
chat.pc.onconnectionstatechange = () => {
|
||||
console.log('iceConnectionState changed', chat.pc.iceConnectionState);
|
||||
switch (chat.pc.iceConnectionState) {
|
||||
case 'connected':
|
||||
break;
|
||||
case 'disconnected':
|
||||
this.callClosed(pub);
|
||||
break;
|
||||
case 'new':
|
||||
//this.callClosed(pub);
|
||||
break;
|
||||
case 'failed':
|
||||
this.callClosed(pub);
|
||||
break;
|
||||
case 'closed':
|
||||
this.callClosed(pub);
|
||||
break;
|
||||
default:
|
||||
console.log('Change of state', chat.pc.iceConnectionState);
|
||||
break;
|
||||
}
|
||||
};
|
||||
chat.pc.ontrack = (event) => {
|
||||
console.log('ontrack', event);
|
||||
const remoteVideo = $('#remotevideo');
|
||||
if (remoteVideo[0].srcObject !== event.streams[0]) {
|
||||
remoteVideo[0].srcObject = event.streams[0];
|
||||
remoteVideo[0].onloadedmetadata = function () {
|
||||
console.log('metadata loaded');
|
||||
remoteVideo[0].play();
|
||||
};
|
||||
console.log('received remote stream', event);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const resizeButton = html`<span
|
||||
style="cursor:pointer;margin-left:15px;font-size:2em;position:absolute;left:0;top:0"
|
||||
onClick=${() => this.setState({ maximized: !this.state.maximized })}
|
||||
>${this.state.maximized ? '-' : '+'}</span
|
||||
>`;
|
||||
const width = this.state.maximized ? '100%' : '400px';
|
||||
const height = this.state.maximized ? '100%' : '400px';
|
||||
const bottom = this.state.maximized ? '0' : '70px';
|
||||
const localVideo = html`<video
|
||||
id="localvideo"
|
||||
autoplay="true"
|
||||
playsinline="true"
|
||||
style="width:50%;max-height:60%"
|
||||
/>`;
|
||||
const remoteVideo = html`<video
|
||||
id="remotevideo"
|
||||
autoplay="true"
|
||||
playsinline="true"
|
||||
style="width:50%;max-height:60%"
|
||||
/>`;
|
||||
|
||||
if (this.state.activeCall) {
|
||||
return html` <div
|
||||
id="active-call"
|
||||
style="position: fixed; right:0; bottom: ${bottom}; height:${height}; width: ${width}; max-width: 100%; text-align: center; background: #000; color: #fff; padding: 15px 0"
|
||||
>
|
||||
<div style="margin-bottom:5px;position:relative;height:50px;">
|
||||
${resizeButton} ${t('on_call_with')}
|
||||
${iris.private(this.state.activeCall) && iris.private(this.state.activeCall).name}
|
||||
</div>
|
||||
${localVideo} ${remoteVideo}
|
||||
<${Button}
|
||||
style="display:block;margin:15px auto"
|
||||
onClick=${() => this.endCall(this.state.activeCall)}
|
||||
>End call<//
|
||||
>
|
||||
</div>`;
|
||||
} else if (this.state.outgoingCall) {
|
||||
return html`<div
|
||||
id="outgoing-call"
|
||||
style="position:fixed; right:0; bottom: ${bottom}; height:${height}; width: ${width}; text-align: center; background: #000; color: #fff; padding: 15px"
|
||||
>
|
||||
${t('calling')} ${iris.private(this.state.outgoingCall).name}
|
||||
<${Button}
|
||||
onClick=${() => this.cancelCall(this.state.outgoingCall)}
|
||||
style="display:block; margin: 15px auto"
|
||||
>
|
||||
${t('cancel')}
|
||||
<//>
|
||||
${localVideo} ${remoteVideo}
|
||||
</div>`;
|
||||
} else if (this.state.incomingCall) {
|
||||
return html`
|
||||
<div
|
||||
id="incoming-call"
|
||||
style="position:fixed; right:0; bottom: ${bottom}; height:${height}; width: ${width}; text-align: center; background: #000; color: #fff; padding: 15px 0"
|
||||
>
|
||||
Incoming call from ${iris.private(this.state.incomingCall).name}
|
||||
<${Button}
|
||||
style="display:block; margin: 15px auto"
|
||||
onClick=${() => this.answerCall(this.state.incomingCall)}
|
||||
>${t('answer')}<//
|
||||
>
|
||||
<${Button}
|
||||
style="display:block; margin: 15px auto"
|
||||
onClick=${() => this.rejectCall(this.state.incomingCall)}
|
||||
>${t('reject')}<//
|
||||
>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default VideoCall;
|
||||
export { RTC_CONFIG, DEFAULT_RTC_CONFIG, setRTCConfig, getRTCConfig };
|
@ -6,7 +6,6 @@ import BetaSettings from './BetaSettings';
|
||||
import BlockedSettings from './BlockedSettings';
|
||||
import LanguageSettings from './LanguageSettings';
|
||||
import NostrSettings from './NostrSettings';
|
||||
import WebRTCSettings from './WebRTCSettings';
|
||||
import WebtorrentSettings from './WebtorrentSettings';
|
||||
|
||||
export default class SettingsContent extends Component {
|
||||
@ -17,7 +16,6 @@ export default class SettingsContent extends Component {
|
||||
appearance: AppearanceSettings,
|
||||
language: LanguageSettings,
|
||||
webtorrent: WebtorrentSettings,
|
||||
webrtc: WebRTCSettings,
|
||||
beta: BetaSettings,
|
||||
blocked_users: BlockedSettings,
|
||||
};
|
||||
|
@ -1,77 +0,0 @@
|
||||
import iris from 'iris-lib';
|
||||
import $ from 'jquery';
|
||||
|
||||
import Component from '../../BaseComponent';
|
||||
import Button from '../../components/basic/Button';
|
||||
import { DEFAULT_RTC_CONFIG, getRTCConfig, setRTCConfig } from '../../components/VideoCall';
|
||||
import { translate as t } from '../../translations/Translation';
|
||||
|
||||
export default class WebRTCSettings extends Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<div class="centered-container">
|
||||
<h3>{t('webrtc_connection_options')}</h3>
|
||||
<p>
|
||||
<textarea
|
||||
rows="4"
|
||||
id="rtc-config"
|
||||
placeholder={t('webrtc_connection_options')}
|
||||
onChange={(e) => this.rtcConfigChanged(e)}
|
||||
/>
|
||||
</p>
|
||||
<Button onClick={() => this.restoreDefaultRtcConfig()}>{t('restore_defaults')}</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const blockedUsers = {};
|
||||
|
||||
$('#rtc-config').val(JSON.stringify(getRTCConfig()));
|
||||
|
||||
iris.electron && iris.electron.get('settings').on(this.inject('electron', 'electron'));
|
||||
iris
|
||||
.local()
|
||||
.get('settings')
|
||||
.on(
|
||||
this.sub((local) => {
|
||||
console.log('local settings', local);
|
||||
if (local) {
|
||||
this.setState({ local });
|
||||
}
|
||||
}),
|
||||
);
|
||||
iris
|
||||
.public()
|
||||
.get('webPushSubscriptions')
|
||||
.map()
|
||||
.on(
|
||||
this.sub(() =>
|
||||
this.setState({
|
||||
webPushSubscriptions: iris.notifications.webPushSubscriptions,
|
||||
}),
|
||||
),
|
||||
);
|
||||
iris
|
||||
.public()
|
||||
.get('block')
|
||||
.map()
|
||||
.on(
|
||||
this.sub((v, k) => {
|
||||
blockedUsers[k] = v;
|
||||
this.setState({ blockedUsers });
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
rtcConfigChanged(e) {
|
||||
setRTCConfig(JSON.parse(e.target.value));
|
||||
}
|
||||
|
||||
restoreDefaultRtcConfig() {
|
||||
setRTCConfig(DEFAULT_RTC_CONFIG);
|
||||
$('#rtc-config').val(JSON.stringify(getRTCConfig()));
|
||||
}
|
||||
}
|
@ -14,7 +14,12 @@ registerRoute(
|
||||
plugins: [bgSyncPlugin],
|
||||
}),
|
||||
);
|
||||
registerRoute(({ url }) => url.pathname === '/', new NetworkFirst());
|
||||
registerRoute(
|
||||
({ url }) => url.pathname === '/',
|
||||
new NetworkFirst({
|
||||
networkTimeoutSeconds: 5,
|
||||
}),
|
||||
);
|
||||
registerRoute(
|
||||
({ url }) => {
|
||||
return location.host.indexOf('localhost') !== 0 && url.origin === self.location.origin;
|
||||
|
Loading…
Reference in New Issue
Block a user