[call-me] - feat: use RINGING_TIMEOUT env var for call timeout, dynamic progress bar, and looping ring sound
This commit is contained in:
+5
-1
@@ -76,4 +76,8 @@ PUSH_VAPID_EMAIL='mailto:admin@example.com'
|
||||
SENTRY_ENABLED=false # true or false
|
||||
SENTRY_LOG_LEVELS=error # Log levels to capture in Sentry (e.g., error,warn)
|
||||
SENTRY_DSN=
|
||||
SENTRY_TRACES_SAMPLE_RATE=0.5 # Adjust the sample rate for performance monitoring (0.0 to 1.0)
|
||||
SENTRY_TRACES_SAMPLE_RATE=0.5 # Adjust the sample rate for performance monitoring (0.0 to 1.0)
|
||||
|
||||
# Time in seconds before a call is considered unanswered (default 30 seconds)
|
||||
|
||||
RINGING_TIMEOUT=30
|
||||
@@ -92,6 +92,7 @@ const config = {
|
||||
pushVapidPrivateKey: process.env.PUSH_VAPID_PRIVATE_KEY || '',
|
||||
pushVapidEmail: process.env.PUSH_VAPID_EMAIL || 'mailto:admin@example.com',
|
||||
randomImageUrl: process.env.RANDOM_IMAGE_URL || '',
|
||||
ringTimeout: parseInt(process.env.RINGING_TIMEOUT, 10) || 30,
|
||||
apiBasePath: '/api/v1',
|
||||
swaggerDocument: yaml.load(fs.readFileSync(path.join(__dirname, '/api/swagger.yaml'), 'utf8')),
|
||||
};
|
||||
@@ -529,6 +530,7 @@ function handleConnection(socket) {
|
||||
message: 'Hello Client!',
|
||||
iceServers: config.iceServers,
|
||||
pushEnabled: config.pushEnabled,
|
||||
ringTimeout: config.ringTimeout,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Generated
+21
-66
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "call-me",
|
||||
"version": "1.3.44",
|
||||
"version": "1.3.45",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "call-me",
|
||||
"version": "1.3.44",
|
||||
"version": "1.3.45",
|
||||
"license": "AGPLv3",
|
||||
"dependencies": {
|
||||
"@ngrok/ngrok": "1.7.0",
|
||||
"@sentry/node": "^10.51.0",
|
||||
"@sentry/node": "^10.52.0",
|
||||
"axios": "^1.16.0",
|
||||
"colors": "^1.4.0",
|
||||
"cors": "^2.8.6",
|
||||
@@ -522,23 +522,6 @@
|
||||
"@opentelemetry/api": ">=1.0.0 <1.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/instrumentation-ioredis": {
|
||||
"version": "0.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.62.0.tgz",
|
||||
"integrity": "sha512-ZYt//zcPve8qklaZX+5Z4MkU7UpEkFRrxsf2cnaKYBitqDnsCN69CPAuuMOX6NYdW2rG9sFy7V/QWtBlP5XiNQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@opentelemetry/instrumentation": "^0.214.0",
|
||||
"@opentelemetry/redis-common": "^0.38.2",
|
||||
"@opentelemetry/semantic-conventions": "^1.33.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/instrumentation-kafkajs": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.23.0.tgz",
|
||||
@@ -690,23 +673,6 @@
|
||||
"@opentelemetry/api": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/instrumentation-redis": {
|
||||
"version": "0.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.62.0.tgz",
|
||||
"integrity": "sha512-y3pPpot7WzR/8JtHcYlTYsyY8g+pbFhAqbwAuG5bLPnR6v6pt1rQc0DpH0OlGP/9CZbWBP+Zhwp9yFoygf/ZXQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@opentelemetry/instrumentation": "^0.214.0",
|
||||
"@opentelemetry/redis-common": "^0.38.2",
|
||||
"@opentelemetry/semantic-conventions": "^1.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/instrumentation-tedious": {
|
||||
"version": "0.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.33.0.tgz",
|
||||
@@ -724,15 +690,6 @@
|
||||
"@opentelemetry/api": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/redis-common": {
|
||||
"version": "0.38.3",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.38.3.tgz",
|
||||
"integrity": "sha512-VCghU1JYs/4gP6Gqf/xro9MEsZ7LrMv2uONVsaESKL38ZOB9BqnI98FfS23wjMnHlpuE+TTaWSoAVNpTwYXzjw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/resources": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.1.tgz",
|
||||
@@ -844,18 +801,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "10.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.51.0.tgz",
|
||||
"integrity": "sha512-Y45V/YXvVLEXmOdkbD1oG1gkRWFi9guCEGg3PlIlIpRjAbZUrvLGgjRJIc1E7XpSzmOnWbs5BbUxMv4PDaPj2w==",
|
||||
"version": "10.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.52.0.tgz",
|
||||
"integrity": "sha512-VA/kAqLhkMnRWY2RXdBLyTemR9D4m7MVRy/gyapoq9yvllVPx9WXbvKgnMP2LQp7mFgT/oLFvw58aQKaYTGn3A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/node": {
|
||||
"version": "10.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.51.0.tgz",
|
||||
"integrity": "sha512-2yZLRZwS1dKG8/4eOTpGSo/gO/EgmT9aPj6lAzUkRa7bZCTTdW4BraaHU0leX5T94909Qfhbr3W5AVTfDOCKiQ==",
|
||||
"version": "10.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.52.0.tgz",
|
||||
"integrity": "sha512-9+p3KJUk3rHO1HOEZuSknP2RgKCJZONDm4HWgkVDtVBtocb66KLtVlMjc59d2/bWP7tM3wc877tpG30quFfU9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fastify/otel": "0.18.0",
|
||||
@@ -870,7 +827,6 @@
|
||||
"@opentelemetry/instrumentation-graphql": "0.62.0",
|
||||
"@opentelemetry/instrumentation-hapi": "0.60.0",
|
||||
"@opentelemetry/instrumentation-http": "0.214.0",
|
||||
"@opentelemetry/instrumentation-ioredis": "0.62.0",
|
||||
"@opentelemetry/instrumentation-kafkajs": "0.23.0",
|
||||
"@opentelemetry/instrumentation-knex": "0.58.0",
|
||||
"@opentelemetry/instrumentation-koa": "0.62.0",
|
||||
@@ -880,14 +836,13 @@
|
||||
"@opentelemetry/instrumentation-mysql": "0.60.0",
|
||||
"@opentelemetry/instrumentation-mysql2": "0.60.0",
|
||||
"@opentelemetry/instrumentation-pg": "0.66.0",
|
||||
"@opentelemetry/instrumentation-redis": "0.62.0",
|
||||
"@opentelemetry/instrumentation-tedious": "0.33.0",
|
||||
"@opentelemetry/sdk-trace-base": "^2.6.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.40.0",
|
||||
"@prisma/instrumentation": "7.6.0",
|
||||
"@sentry/core": "10.51.0",
|
||||
"@sentry/node-core": "10.51.0",
|
||||
"@sentry/opentelemetry": "10.51.0",
|
||||
"@sentry/core": "10.52.0",
|
||||
"@sentry/node-core": "10.52.0",
|
||||
"@sentry/opentelemetry": "10.52.0",
|
||||
"import-in-the-middle": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -895,13 +850,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/node-core": {
|
||||
"version": "10.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.51.0.tgz",
|
||||
"integrity": "sha512-VP9DMEzBEuauABrfDHYz/pRYa74M09uRJLz0ls3yel3sKhYHMyCB29ZxbKcciUhD4d33dwgi8DbaPZV2H/wnfQ==",
|
||||
"version": "10.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.52.0.tgz",
|
||||
"integrity": "sha512-IG7MBtLRPQ2LuU+kbD14AFZroZgAeUmJQTP1FI/F8n56O31+p+9R703LuBTpvZr6sm+eRYDMWcGYYkfLHRVjwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "10.51.0",
|
||||
"@sentry/opentelemetry": "10.51.0",
|
||||
"@sentry/core": "10.52.0",
|
||||
"@sentry/opentelemetry": "10.52.0",
|
||||
"import-in-the-middle": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -937,12 +892,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/opentelemetry": {
|
||||
"version": "10.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.51.0.tgz",
|
||||
"integrity": "sha512-Qc7AlCE4uhB+SvHLqah4RgR1WdY7wmmr/hx9g/prDP9R1ocshmUEMrZK9qjuwaklW7/fmkFCXI8ETxo5L1bHIA==",
|
||||
"version": "10.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.52.0.tgz",
|
||||
"integrity": "sha512-Sc7StsvC0bwhMcgDfTRWUIexO5cNzzKUurvUwtpgQUnxO7AzexU3lkY3yHYDsCbWYAEQMXAgQYQtbcqoh+Ie7g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "10.51.0"
|
||||
"@sentry/core": "10.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "call-me",
|
||||
"version": "1.3.44",
|
||||
"version": "1.3.45",
|
||||
"description": "Your Go-To for Instant Video Calls",
|
||||
"author": "Miroslav Pejic - miroslav.pejic.85@gmail.com",
|
||||
"license": "AGPLv3",
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ngrok/ngrok": "1.7.0",
|
||||
"@sentry/node": "^10.51.0",
|
||||
"@sentry/node": "^10.52.0",
|
||||
"axios": "^1.16.0",
|
||||
"colors": "^1.4.0",
|
||||
"cors": "^2.8.6",
|
||||
|
||||
+43
-4
@@ -90,6 +90,8 @@ let callingTimerId = null; // Timer for calling overlay
|
||||
let callingElapsed = 0; // Seconds elapsed while calling
|
||||
let incomingCallData = null; // Pending incoming call data
|
||||
let incomingCallTimerId = null; // Auto-decline timer for incoming call
|
||||
let ringTimeout = 30; // Seconds before unanswered call is auto-cancelled/declined (from server)
|
||||
let ringingAudio = null; // Looping ring sound for incoming call
|
||||
let thisConnection;
|
||||
let camera = 'user';
|
||||
let stream;
|
||||
@@ -777,6 +779,9 @@ function showCallingOverlay(targetUser) {
|
||||
callingTimerId = setInterval(() => {
|
||||
callingElapsed++;
|
||||
if (callingTimer) callingTimer.textContent = callingElapsed + 's';
|
||||
if (callingElapsed >= ringTimeout) {
|
||||
handleCancelCall();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
@@ -1375,6 +1380,9 @@ function handlePing(data) {
|
||||
if (data.pushEnabled !== undefined) {
|
||||
pushEnabled = data.pushEnabled;
|
||||
}
|
||||
if (data.ringTimeout !== undefined) {
|
||||
ringTimeout = data.ringTimeout;
|
||||
}
|
||||
sendMsg({
|
||||
type: 'pong',
|
||||
message: {
|
||||
@@ -1717,7 +1725,6 @@ function offerAccept(data) {
|
||||
|
||||
incomingCallData = data;
|
||||
showIncomingCallOverlay(data.from);
|
||||
sound('ring');
|
||||
}
|
||||
|
||||
// Show incoming call overlay
|
||||
@@ -1725,20 +1732,47 @@ function showIncomingCallOverlay(callerName) {
|
||||
if (!incomingCallOverlay) return;
|
||||
if (incomingCallUsername) incomingCallUsername.textContent = callerName;
|
||||
|
||||
// Reset timer bar animation
|
||||
// Reset timer bar animation with dynamic duration
|
||||
if (incomingCallTimer) {
|
||||
incomingCallTimer.style.setProperty('--ring-duration', ringTimeout + 's');
|
||||
incomingCallTimer.style.animation = 'none';
|
||||
incomingCallTimer.offsetHeight; // Force reflow
|
||||
incomingCallTimer.style.animation = '';
|
||||
}
|
||||
|
||||
// Start looping ring sound with a 1s gap between plays
|
||||
if (ringingAudio) {
|
||||
ringingAudio.pause();
|
||||
ringingAudio = null;
|
||||
}
|
||||
let ringingDelayTimer = null;
|
||||
function playRing() {
|
||||
if (!ringingAudio) return;
|
||||
ringingAudio.currentTime = 0;
|
||||
ringingAudio.play().catch(() => {});
|
||||
}
|
||||
ringingAudio = new Audio('./assets/ring.wav');
|
||||
ringingAudio.volume = 0.5;
|
||||
ringingAudio.addEventListener('ended', () => {
|
||||
ringingDelayTimer = setTimeout(playRing, 3000);
|
||||
});
|
||||
// Store the delay timer on the audio object so hideIncomingCallOverlay can clear it
|
||||
ringingAudio._delayTimer = null;
|
||||
Object.defineProperty(ringingAudio, '_delayTimer', {
|
||||
get: () => ringingDelayTimer,
|
||||
set: (v) => {
|
||||
ringingDelayTimer = v;
|
||||
},
|
||||
});
|
||||
playRing();
|
||||
|
||||
incomingCallOverlay.style.display = 'flex';
|
||||
|
||||
// Auto-decline after 10 seconds
|
||||
// Auto-decline after ringTimeout seconds
|
||||
if (incomingCallTimerId) clearTimeout(incomingCallTimerId);
|
||||
incomingCallTimerId = setTimeout(() => {
|
||||
handleDeclineIncomingCall();
|
||||
}, 10000);
|
||||
}, ringTimeout * 1000);
|
||||
}
|
||||
|
||||
// Hide incoming call overlay
|
||||
@@ -1749,6 +1783,11 @@ function hideIncomingCallOverlay() {
|
||||
clearTimeout(incomingCallTimerId);
|
||||
incomingCallTimerId = null;
|
||||
}
|
||||
if (ringingAudio) {
|
||||
clearTimeout(ringingAudio._delayTimer);
|
||||
ringingAudio.pause();
|
||||
ringingAudio = null;
|
||||
}
|
||||
incomingCallData = null;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3010,7 +3010,7 @@ z-index:
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: linear-gradient(90deg, var(--success-color), var(--primary-color));
|
||||
animation: incomingTimerBar 10s linear forwards;
|
||||
animation: incomingTimerBar var(--ring-duration, 30s) linear forwards;
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user