buzz-me-in 2.2.0-beta.3 → 2.2.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +7 -4
- package/README.md +2 -2
- package/homekit.js +13 -1
- package/package.json +1 -1
- package/server.js +5 -0
- package/src/core/config.js +1 -1
- package/src/core/media-stream.js +30 -0
package/.env.example
CHANGED
|
@@ -58,10 +58,13 @@ SHUTDOWN_GRACE_MS=10000
|
|
|
58
58
|
# How long the Twilio call is held open after the HomeKit live view closes,
|
|
59
59
|
# before the call is hung up. Backing out of the camera view to the room view
|
|
60
60
|
# tears the stream down, and the lock tile there needs the call to still be up
|
|
61
|
-
# to send its DTMF.
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
|
|
61
|
+
# to send its DTMF. Tapping unlock restarts the window, so the digits are never
|
|
62
|
+
# cut short. 8 s is measured, not guessed: closing the view and then reaching
|
|
63
|
+
# the lock tile under Other took 2.9 s unhurried, and 3 s left 78 ms of margin.
|
|
64
|
+
# The cost of a longer window is that much silence for the caller after you are
|
|
65
|
+
# done, so lower it only if that silence bothers a caller more than a rushed
|
|
66
|
+
# unlock bothers you.
|
|
67
|
+
HOMEKIT_HANGUP_GRACE_MS=8000
|
|
65
68
|
|
|
66
69
|
# Logging
|
|
67
70
|
# LOG_LEVEL controls minimum emitted level: debug | info | warn | error
|
package/README.md
CHANGED
|
@@ -448,12 +448,12 @@ Open the live view, then dismiss it on the iPhone (tap the X / end button).
|
|
|
448
448
|
**Pass (server log):**
|
|
449
449
|
|
|
450
450
|
```text
|
|
451
|
-
{"ts":"...","level":"info","message":"Hangup scheduled after grace period","component":"homekit","event":"hangup-scheduled","reason":"homekit-session-stopped","callSid":"CA...","sessionId":"...","graceMs":
|
|
451
|
+
{"ts":"...","level":"info","message":"Hangup scheduled after grace period","component":"homekit","event":"hangup-scheduled","reason":"homekit-session-stopped","callSid":"CA...","sessionId":"...","graceMs":8000}
|
|
452
452
|
{"ts":"...","level":"info","message":"Inbound ffmpeg exited","component":"homekit","event":"ffin-exit","reason":"nonzero-exit","exitCode":null,"sessionId":"..."}
|
|
453
453
|
{"ts":"...","level":"info","message":"Hanging up call","component":"twilio-api","event":"hangup","callSid":"CA..."}
|
|
454
454
|
```
|
|
455
455
|
|
|
456
|
-
The call is not hung up the instant the view closes. It is held open for `HOMEKIT_HANGUP_GRACE_MS` (default
|
|
456
|
+
The call is not hung up the instant the view closes. It is held open for `HOMEKIT_HANGUP_GRACE_MS` (default 8000) so the lock tile still has a call to send DTMF to, then hung up. Reopening the view inside that window logs `hangup-cancelled` instead and the call continues; if the caller hangs up first, the pending hangup logs `hangup-skipped` and does nothing.
|
|
457
457
|
|
|
458
458
|
**Pass (Twilio):** The call shows as completed in the [Twilio Console call log](https://console.twilio.com/us1/monitor/logs/calls).
|
|
459
459
|
|
package/homekit.js
CHANGED
|
@@ -158,6 +158,7 @@ const activeSessions = new Map();
|
|
|
158
158
|
// PassThrough stream set by server.js each time a Twilio call connects.
|
|
159
159
|
let currentMulawStream = null;
|
|
160
160
|
let onHapSessionStarted = null;
|
|
161
|
+
let onHapSessionEnded = null;
|
|
161
162
|
|
|
162
163
|
function getActiveCall() {
|
|
163
164
|
return state.getActiveCall();
|
|
@@ -565,7 +566,13 @@ function _stopSession(sessionID, hangUp) {
|
|
|
565
566
|
// it kills a live call: seen on 2026-09-12, where session ac5c8c21 stopping
|
|
566
567
|
// ended the call under session d332e46a three seconds into the stream.
|
|
567
568
|
const activeCall = getActiveCall();
|
|
568
|
-
if (
|
|
569
|
+
if (activeSessions.size !== 0) return;
|
|
570
|
+
|
|
571
|
+
// ffIn is dead and unpiped by now, so tell the media stream to stop writing
|
|
572
|
+
// into a PassThrough with no consumer. See markHomekitSessionEnded.
|
|
573
|
+
if (activeCall && onHapSessionEnded) onHapSessionEnded(activeCall.callSid);
|
|
574
|
+
|
|
575
|
+
if (hangUp && activeCall) {
|
|
569
576
|
scheduleHangUp(activeCall.callSid, sessionID);
|
|
570
577
|
}
|
|
571
578
|
}
|
|
@@ -888,6 +895,10 @@ function setOnHapSessionStarted(handler) {
|
|
|
888
895
|
onHapSessionStarted = typeof handler === 'function' ? handler : null;
|
|
889
896
|
}
|
|
890
897
|
|
|
898
|
+
function setOnHapSessionEnded(handler) {
|
|
899
|
+
onHapSessionEnded = typeof handler === 'function' ? handler : null;
|
|
900
|
+
}
|
|
901
|
+
|
|
891
902
|
/**
|
|
892
903
|
* Graceful shutdown: tear down streaming sessions and unpublish the
|
|
893
904
|
* accessory so the mDNS advertisement does not linger after exit.
|
|
@@ -923,6 +934,7 @@ module.exports = {
|
|
|
923
934
|
clearMulawPassthrough,
|
|
924
935
|
endHapSession,
|
|
925
936
|
setOnHapSessionStarted,
|
|
937
|
+
setOnHapSessionEnded,
|
|
926
938
|
shutdown,
|
|
927
939
|
// Exported for tests/homekit-hangup-grace.test.cjs. Reaching the deferred
|
|
928
940
|
// hangup through the streaming delegate would mean standing up a full SRTP
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -67,6 +67,11 @@ homekit.setOnHapSessionStarted((callSid) => {
|
|
|
67
67
|
if (mediaStream) mediaStream.markHomekitSessionStarted();
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
+
homekit.setOnHapSessionEnded((callSid) => {
|
|
71
|
+
const mediaStream = activeMediaStreamsByCallSid.get(callSid);
|
|
72
|
+
if (mediaStream) mediaStream.markHomekitSessionEnded();
|
|
73
|
+
});
|
|
74
|
+
|
|
70
75
|
// ---------------------------------------------------------------------------
|
|
71
76
|
// Ringtone — one UK-style ringback cycle (400Hz+450Hz dual tone), generated
|
|
72
77
|
// in-process as a WAV buffer. Served at GET /ringtone for debug/manual
|
package/src/core/config.js
CHANGED
|
@@ -138,7 +138,7 @@ module.exports = {
|
|
|
138
138
|
streamStartTimeoutMs: parsePositiveInt('STREAM_START_TIMEOUT_MS', '3000'),
|
|
139
139
|
twilioMediaPayloadMaxBytes: parsePositiveInt('TWILIO_MEDIA_PAYLOAD_MAX_BYTES', '512'),
|
|
140
140
|
shutdownGraceMs: parsePositiveInt('SHUTDOWN_GRACE_MS', '10000'),
|
|
141
|
-
homekitHangupGraceMs: parsePositiveInt('HOMEKIT_HANGUP_GRACE_MS', '
|
|
141
|
+
homekitHangupGraceMs: parsePositiveInt('HOMEKIT_HANGUP_GRACE_MS', '8000'),
|
|
142
142
|
streamAuthSecret,
|
|
143
143
|
streamAuthTtlSec: 90,
|
|
144
144
|
statusApiToken,
|
package/src/core/media-stream.js
CHANGED
|
@@ -293,6 +293,36 @@ class MediaStream {
|
|
|
293
293
|
this.stopRingback('homekit-session-started');
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
+
/**
|
|
297
|
+
* The counterpart to markHomekitSessionStarted, called once the last HomeKit
|
|
298
|
+
* streaming session stops.
|
|
299
|
+
*
|
|
300
|
+
* Without it, forwarding stayed on for the life of the call while the
|
|
301
|
+
* PassThrough's consumer was gone: _stopSession kills ffIn and unpipes it, so
|
|
302
|
+
* Twilio audio accumulated in a buffer nobody drained. That matters twice
|
|
303
|
+
* over. The buffer holds 4 s (32 KB of 8 kHz mu-law), so a longer gap logs
|
|
304
|
+
* media-frames-dropped for audio that was never going anywhere; and on
|
|
305
|
+
* reopening the live view the new ffIn inherits the backlog and drains it
|
|
306
|
+
* faster than real time, which is the "buffered startup audio burst" the
|
|
307
|
+
* inbound spawn comment already warns about. Either way a rejoin starts
|
|
308
|
+
* behind live instead of at it.
|
|
309
|
+
*
|
|
310
|
+
* This restores the invariant the write path documents: forward live-view
|
|
311
|
+
* audio only.
|
|
312
|
+
*/
|
|
313
|
+
markHomekitSessionEnded() {
|
|
314
|
+
if (!this.hasHomekitSession) return;
|
|
315
|
+
this.hasHomekitSession = false;
|
|
316
|
+
// Otherwise a later resume would log against a run of drops that ended
|
|
317
|
+
// when forwarding stopped.
|
|
318
|
+
this.droppingFrames = false;
|
|
319
|
+
this.logger.info('HomeKit session ended; no longer forwarding media', {
|
|
320
|
+
callSid: this.currentCallSid || undefined,
|
|
321
|
+
event: 'homekit-session-ended',
|
|
322
|
+
reason: 'no-active-hap-session',
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
296
326
|
sendRingbackFrame() {
|
|
297
327
|
if (!this.currentCallSid || !this.started || this.closed) return;
|
|
298
328
|
|