diff --git a/server/pruef-anruf.mjs b/server/pruef-anruf.mjs index 692b7fe9..2782cbac 100644 --- a/server/pruef-anruf.mjs +++ b/server/pruef-anruf.mjs @@ -631,6 +631,30 @@ melde("=== 7. Im Browser ==="); viewport: { width: 1280, height: 900 }, permissions: ["microphone", "camera"], }); + + /* TOENE MITZAEHLEN -- vor allem anderen. + + Filipe: „ist das normal dass es nicht mal klingelt wenn man + anruft?" Nein: Es gab gar keinen Ton. Der Anruf zeigte einen + Kasten, sonst nichts. + + Gemessen wird am Oszillator, nicht am Lautsprecher. Ob wirklich + etwas zu hoeren ist, haengt an Geraet, Lautstaerke und daran, + ob der Browser Ton schon erlaubt -- das kann keine Pruefung + beantworten. Dass die Seite Toene ERZEUGT, kann sie sehr wohl. + + `addInitScript` laeuft vor jedem Skript der Seite; danach + waere der Zaehler zu spaet. */ + await sicht.addInitScript(() => { + window.__toene = 0; + const K = window.AudioContext || window.webkitAudioContext; + if (!K) return; + const alt = K.prototype.createOscillator; + K.prototype.createOscillator = function (...w) { + window.__toene = (window.__toene || 0) + 1; + return alt.apply(this, w); + }; + }); await sicht.addCookies(kDogi.split("; ").map((c) => { const [name, ...rest] = c.split("="); return { name, value: rest.join("="), domain: "127.0.0.1", path: "/" }; @@ -676,6 +700,11 @@ melde("=== 7. Im Browser ==="); `und sagt, was gerade passiert ("${kasten.lage}")`); ok(/^\d\d:\d\d$/.test(kasten.zeit), `die Uhr laeuft (${kasten.zeit})`); + /* Und es klingelt hoerbar. Waere der Ton wieder ausgebaut, + stuende hier 0. */ + const toene = await seite.evaluate(() => window.__toene ?? -1); + ok(toene > 0, `es klingelt hoerbar -- ${toene} Toene erzeugt`); + /* Und der Server weiss davon. */ const l = json(await roh(`/workspace/api/anruf/${raumId}`, HAUS, { cookie: kDogi })); ok(l.laeuft === true, "der Server kennt den Anruf"); diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index 020af340..19706be4 100644 --- a/workspace/app.webmanifest +++ b/workspace/app.webmanifest @@ -22,25 +22,25 @@ }, "icons": [ { - "src": "/assets/img/app-symbole/workspace-192.png?v=202609182330", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609182358", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609182330", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609182358", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609182330", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609182358", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609182330", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609182358", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/assets/js/anruf.js b/workspace/assets/js/anruf.js index 5230f1ed..ff225590 100644 --- a/workspace/assets/js/anruf.js +++ b/workspace/assets/js/anruf.js @@ -159,7 +159,12 @@ }; v.onconnectionstatechange = () => { - if (v.connectionState === 'connected') lage('Verbunden'); + if (v.connectionState === 'connected') { + /* Ab hier redet man miteinander -- ein Freizeichen daneben + waere das, was man an einer Telefonanlage hasst. */ + tonAus(); + lage('Verbunden'); + } /* `failed` heisst: Es kommt nichts mehr. Das gehoert gesagt -- ein Kasten, der ewig „Verbindung …" zeigt, laesst einen warten, wo nichts mehr kommt. */ @@ -268,6 +273,9 @@ $('anruf-video').hidden = !mitVideo; if (mitVideo) $('anruf-video').setAttribute('aria-pressed', 'true'); lage('Es klingelt …'); + /* DAS FREIZEICHEN. Ein stiller Kasten mit laufender Uhr sagt nur, + dass etwas passiert -- nicht, was. */ + freiTon(); uhrLaufen(); const a = await fetch(`/workspace/api/anruf/${raumId}/start`, { @@ -334,6 +342,7 @@ } async function auflegen(melden) { + tonAus(); klingelnAus(); if (!anruf) { const k = $('anruf'); if (k) k.hidden = true; return; } const raumId = anruf.raumId; @@ -525,6 +534,9 @@ function klingelnZeigen(raumId, von, mitVideo) { klingelnAus(); + /* UND ES KLINGELT WIRKLICH. Vorher stand hier nur ein Kasten -- + wer nicht zufaellig hinsah, merkte nichts. */ + klingelTon(); const k = el('div', 'anruf-klingelt'); k.id = 'anruf-klingelt'; k.setAttribute('role', 'alertdialog'); @@ -548,7 +560,87 @@ zu einem Gespräch da, an dem längst niemand mehr teilnimmt. */ setTimeout(klingelnAus, 46000); } - function klingelnAus() { $('anruf-klingelt')?.remove(); } + /* ---------- DER KLINGELTON (18.09.2026) -------------------------- + + Filipe: „ist das normal dass es nicht mal klingelt wenn man + anruft?" + + Nein. Es gab gar keinen Ton -- weder beim Anrufer noch beim + Angerufenen. Ein Anruf zeigte einen Kasten auf dem Bildschirm, + sonst nichts. Wer nicht zufaellig hinsah, merkte nichts; und wer + anrief, wusste nie, ob ueberhaupt etwas passiert. Genau das + fuehlt sich an wie „geht nicht". + + OHNE TONDATEI. Ein Klingelton als .mp3 waere eine Datei mehr im + Netz, eine Lizenzfrage und ein Ladefehler, der genau dann + auffaellt, wenn man ihn braucht. Zwei Sinustoene aus dem Browser + reichen -- das ist, was ein Telefon auch tut. + + LEISE UND KURZ. Kein durchdringendes Schrillen: zwei weiche + Toene, dann Pause. Das traegt durch einen Raum, ohne jemanden zu + erschrecken -- dieselbe Ueberlegung wie bei allem Sichtbaren hier. + + WARUM ES TROTZDEM STUMM BLEIBEN KANN: Browser lassen Ton erst zu, + wenn jemand auf der Seite etwas angeklickt hat. Wer die Seite + gerade erst geoeffnet hat, hoert deshalb unter Umstaenden nichts + -- dann bleibt die Benachrichtigung des Geraets der Weg. Das ist + eine Regel des Browsers, keine Entscheidung von uns. */ + + let tonWerk = null; /* der Taktgeber, solange es klingelt */ + let tonRaum = null; /* AudioContext -- erst bei Bedarf */ + + function tonAn(hoehe, laenge, lautstaerke) { + try { + if (!tonRaum) { + const K = window.AudioContext || window.webkitAudioContext; + if (!K) return; + tonRaum = new K(); + } + if (tonRaum.state === 'suspended') tonRaum.resume().catch(() => {}); + const o = tonRaum.createOscillator(); + const v = tonRaum.createGain(); + o.type = 'sine'; + o.frequency.value = hoehe; + /* Sanft ein und aus: Ein hart geschalteter Sinus knackt, und + genau das Knacken ist das Unangenehme daran. */ + const t = tonRaum.currentTime; + v.gain.setValueAtTime(0, t); + v.gain.linearRampToValueAtTime(lautstaerke, t + 0.03); + v.gain.linearRampToValueAtTime(0, t + laenge); + o.connect(v).connect(tonRaum.destination); + o.start(t); + o.stop(t + laenge + 0.05); + } catch { /* kein Ton -- die Benachrichtigung bleibt der Weg */ } + } + + /** Es klingelt bei dem, der angerufen wird: zwei Toene, dann Pause. */ + function klingelTon() { + tonAus(); + const takt = () => { tonAn(880, 0.22, 0.16); setTimeout(() => tonAn(660, 0.26, 0.16), 300); }; + takt(); + tonWerk = setInterval(takt, 2400); + /* Und das Geraet darf mitvibrieren, wo es das kann. */ + try { navigator.vibrate?.([250, 200, 250]); } catch { /* egal */ } + } + + /** Das Freizeichen bei dem, der anruft -- leiser und langsamer. + * + * Damit er weiss, DASS es laeuft. Ein stiller Kasten mit einer + * laufenden Uhr sagt nur, dass etwas passiert; ein Freizeichen + * sagt, WAS. */ + function freiTon() { + tonAus(); + const takt = () => tonAn(440, 0.5, 0.07); + takt(); + tonWerk = setInterval(takt, 3000); + } + + function tonAus() { + if (tonWerk) { clearInterval(tonWerk); tonWerk = null; } + try { navigator.vibrate?.(0); } catch { /* egal */ } + } + + function klingelnAus() { tonAus(); $('anruf-klingelt')?.remove(); } /* ---------- Was vom Server kommt --------------------------------------- */ @@ -561,6 +653,9 @@ return; } if (d.art === 'dabei') { + /* Jemand ist rangegangen -- auch wenn die Verbindung noch ein + paar Sekunden braucht, klingelt hier nichts mehr. */ + tonAus(); if (!anruf || d.raum_id !== anruf.raumId) return; if (d.person?.id === ichId) return; /* NICHT „Verbunden" MELDEN, SOLANGE NICHTS VERBUNDEN IST. diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index 087df9b7..710efe72 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -12,19 +12,19 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - +
@@ -291,10 +291,10 @@ - - - - - + + + + +