← back to Butlr
live page: chime on every new call (two-tone Web Audio beep, fires on new call ids)
4ef812b656844f06a0993fbc92c635cea1ccc86c · 2026-05-26 10:00:56 -0700 · SteveStudio2
Files touched
Diff
commit 4ef812b656844f06a0993fbc92c635cea1ccc86c
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date: Tue May 26 10:00:56 2026 -0700
live page: chime on every new call (two-tone Web Audio beep, fires on new call ids)
---
routes/live.js | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/routes/live.js b/routes/live.js
index 38a0de5..ef43e30 100644
--- a/routes/live.js
+++ b/routes/live.js
@@ -112,7 +112,7 @@ function renderLive(calls) {
<span class="count"><span id="liveCount">${live.length}</span> active</span>
<span class="sub" style="margin-left:auto">auto-refresh 3s · click 🔊 Listen to hear live (no page reload)</span>
</header>
- <div id="audio-unlock-banner" onclick="unlockAudio()" style="background:#22c55e;color:#022;text-align:center;padding:10px;font-weight:700;cursor:pointer;font-size:14px;">🔊 CLICK HERE ONCE TO ENABLE LIVE AUDIO — then calls play automatically as they connect</div>
+ <div id="audio-unlock-banner" onclick="unlockAudio()" style="background:#22c55e;color:#022;text-align:center;padding:10px;font-weight:700;cursor:pointer;font-size:14px;">🔊 CLICK HERE ONCE TO ENABLE SOUND — chime on every new call + live audio plays automatically as calls connect</div>
<div style="display:none">
</div>
<main id="grid">${cardsHtml}</main>
@@ -128,6 +128,14 @@ function renderLive(calls) {
// Map of callId → { ws, audioCtx, btn, stateEl }
const sessions = new Map();
+ // Call IDs we've already announced with a chime. Seeded on load from the
+ // server-rendered cards so we DON'T beep for calls already on screen —
+ // only for genuinely new calls that arrive after the page is open.
+ const seenCallIds = new Set();
+ document.querySelectorAll('#grid .card[data-id]').forEach(function(el){
+ seenCallIds.add(el.dataset.id);
+ });
+
// Shared AudioContext — browsers require a user gesture to start audio.
// We unlock ONE context on the first click anywhere, then reuse it for every
// call so auto-play-on-connect actually produces sound.
@@ -156,6 +164,30 @@ function renderLive(calls) {
document.addEventListener('click', unlockAudio, { once: false });
document.addEventListener('keydown', unlockAudio, { once: false });
+ // Two-tone ascending chime (no audio asset needed) — fired whenever a NEW
+ // call appears in the grid so Steve hears "a call is being made" even before
+ // the called party picks up (the live stream is silent until they speak).
+ // Needs the shared AudioContext unlocked first (the green banner does that).
+ function playChime() {
+ if (!audioUnlocked) return;
+ try {
+ const ctx = ensureCtx();
+ const t0 = ctx.currentTime + 0.01;
+ [[880, t0, 0.12], [1318.5, t0 + 0.13, 0.18]].forEach(function(spec){
+ const freq = spec[0], start = spec[1], dur = spec[2];
+ const osc = ctx.createOscillator();
+ const gain = ctx.createGain();
+ osc.type = 'sine';
+ osc.frequency.value = freq;
+ gain.gain.setValueAtTime(0.0001, start);
+ gain.gain.exponentialRampToValueAtTime(0.25, start + 0.02);
+ gain.gain.exponentialRampToValueAtTime(0.0001, start + dur);
+ osc.connect(gain); gain.connect(ctx.destination);
+ osc.start(start); osc.stop(start + dur + 0.02);
+ });
+ } catch (e) {}
+ }
+
function getScheme() { return location.protocol === 'https:' ? 'wss:' : 'ws:'; }
function startListen(callId, sampleRate, btn, stateEl) {
@@ -251,6 +283,14 @@ function renderLive(calls) {
const liveIds = new Set(calls.map(c => c.id));
document.getElementById('liveCount').textContent = calls.length;
+ // Chime for any call we haven't announced yet — a call was just made.
+ calls.forEach((c) => {
+ if (!seenCallIds.has(c.id)) {
+ seenCallIds.add(c.id);
+ playChime();
+ }
+ });
+
// Remove cards for calls that ended — unless we're listening to them (keep so user
// can finish hearing the wind-down before WS closes from the server side).
document.querySelectorAll('.card').forEach((el) => {
← 56de574 live page: completed-calls history + reconcile prod drift
·
back to Butlr
·
butlr: live-listen now broadcasts BOTH call tracks (inbound 5ed99e3 →