Screen callers on the office phone
How the folly PBX screens unknown callers on line 4 and hands them to the ElevenLabs troll agent, how to add or remove a contact who skips the screen, what the star codes do, how to render the prompts, and how to test the screen.
The folly PBX answers unknown callers on line 4 and asks them to press 5. This runbook adds and removes a contact who skips that screen, lists the star codes, renders the prompts and tests the screen after a merge. Operate the office phone covers the lines, the trunks and a failed call.
How the screen works#
- Only line 4 screens. Its trunk carries
SCREEN=yesinclusters/folly/apps/pbx/config/pjsip.conf. Line 1 does not screen: the handset dials 911 on it, and 911 calls back there. config/inbound.confrings a contact, an unscreened line, and a screened line within an hour of a 911 from the handset. It answers anyone else and plays the press-5 prompt twice. A 5 rings the handset as[5] <number>. Any other answer goes toconfig/agent.conf, which dials Jonathan, the troll agent on ElevenLabs, for up to ten minutes.- Before it dials Jonathan,
config/agent.conftransfers the caller with a SIP REFER to the voip.ms internal extension inPBX_TROLL_EXTENSION, which belongs to the168847_elevenlabssub-account that the offsite PBX registers. voip.ms moves the call and folly drops out of it. Folly dials Jonathan itself only when voip.ms refuses the transfer, and the sinks below hold whoever he does not take. A transfer voip.ms challenges for credentials, or does not finish in 45 seconds, goes to the sinks instead, since voip.ms may still move that caller.PBX_TROLL_EXTENSIONis empty inpbx-envuntil the owner sets it (Turn on the offsite hand-off), and while it is empty folly keeps every call. - A call that rings the handset buffers the caller's audio with an adaptive jitterbuffer before the handset hears it. The prompt and Jonathan's calls do not.
- Folly's daily count covers both sites: it counts each call Jonathan answers on folly and each call that ends on folly during or after its transfer, and at twenty folly neither transfers nor dials. Folly's two-call cap covers only the calls folly keeps; offsite and ElevenLabs cap the ones it hands on.
- When the agent is off, is on two calls, has taken twenty today, or does
not answer in 60 seconds,
config/spam.confholds the caller for up to ten minutes in the Endless Queue or with Robo-Lenny. Two callers hear the prompt at once and three are held: the next stranger gets a busy signal, and the next held caller hears goodbye. - A contact rings as
[OK] <name>with the Friend ring; a caller who pressed 5 rings with the Human ring. Both areRing10andRing11inprovision/cathy.xml. - Each step logs one line,
pbx-event kind=<kind> line=<line> caller=<digits>, fromconfig/events.conf.kind=trollis a hand-off,kind=held sink=trolla call Jonathan answered, andwhy=onkind=troll-misssays why he did not take one. The PBX dashboard countskind=screened, and so does the Smiirl counter. kind=troll site=offsiteis a transfer attempt, andkind=troll-miss site=offsite why=<status>one that did not happen, which folly's ownkind=trollfollows when folly dials Jonathan itself:why=FAILURE-<code>names the SIP code voip.ms answered with,why=FAILURE-500is also a REFER voip.ms never answered,why=FAILURE-1a REFER that Asterisk could not send or whose subscription ended with no final status,why=FAILUREwith no code a transfer Asterisk could not start, andwhy=timeoutone voip.ms does not finish in 45 seconds.
Before you start#
- Get access to the
homelabvault in 1Password. - Get
kubectlaccess to folly (Get cluster admin access).
Turn on the offsite hand-off#
note
A caller voip.ms takes leaves folly for good: if the offsite PBX does not
answer the extension, folly cannot fall back to its own Jonathan or the sinks.
Set the extension only while pjsip show registrations on offsite lists
the one registration clusters/offsite/apps/pbx/config/pjsip.conf declares
as Registered. Each row names the registration and its auth, never the
sub-account; pjsip show registration <name> shows 168847_elevenlabs in
its client_uri.
In the voip.ms portal, turn on the internal extension of the sub-account
168847_elevenlabsand note the number voip.ms assigns.Set
PBX_TROLL_EXTENSIONto that number in thepbx-envliterals inclusters/folly/apps/pbx/kustomization.yaml, open a PR, and merge it whencore show channelsshows no active call. The merge rolls the pod.Result: after the pod starts,
dialplan show dial@agentshowsTransfer(sip:<extension>@...).Call line 4 from a number that is not a contact, and press nothing.
Result: Jonathan answers. The folly log has
pbx-event kind=trollwithsite=offsiteand nokind=troll-misswithsite=offsite, andcore show channelson folly shows no active call.
Add a contact#
note
A contact's name and number are in the PBX log in VictoriaLogs each time they call. The item is not the only copy.
In the
homelabvault, open the itempbx contacts, or create it as a Secure Note. Keep one item with that title.Add a text field. Make the label the name the handset shows and the value the ten-digit number, in any North American format. Keep every label in the item unique.
note
External Secrets fails the item on a repeated label or a second item with the title, and then no contact skips the screen.
Make sure the ExternalSecret has synced. It refreshes every hour, and the pod's copy of the Secret follows within a minute or two.
kubectl --context folly -n pbx get externalsecret pbx-contactsResult:
STATUSisSecretSynced.Reload the dialplan. Asterisk reads the contacts file when the dialplan loads, and nothing restarts the pod for this Secret.
kubectl --context folly -n pbx exec deploy/pbx -c asterisk -- \ /bin/asterisk -C /etc/asterisk/asterisk.conf -rx 'dialplan reload'Result:
Dialplan reloaded.dialplan show globalsthen lists oneCONTACT_<ten digits>line per contact.
Remove a contact#
note
A reload sets the globals the file still holds and clears none; only a restart forgets one. Delete the field, not the item: External Secrets keeps the Secret of a deleted item.
Delete the contact's field from the
pbx contactsitem.Make sure the ExternalSecret has synced, as in step 3 of Add a contact.
Make sure
core show channelsshows no active call, then restart the pod.kubectl --context folly -n pbx rollout restart deploy/pbxResult: after the pod starts,
dialplan show globalslists noCONTACT_line for the number.
Star codes#
Dial a code from any line. config/handset-codes.conf sends each one to
config/toybox.conf.
| Code | What it does |
|---|---|
*20 | Echo test |
*21 | Talking clock, in the lab's time zone |
*22 | A Morse greeting |
*23 | Milliwatt tone |
*24 | The monkeys |
*25 | Listen to the held callers and the agent's calls; an error tone if there are none |
*26 | The number of callers the sinks have held since the pod started |
*27 | Robo-Lenny |
*28 | The Endless Queue |
*29 | Jonathan, the troll agent, in desk mode; an error tone if he does not answer |
Render the prompts#
clusters/folly/apps/pbx/sounds/lines.yaml declares each prompt.
mise run pbx:voices renders the lines that have no .ulaw beside them with
ElevenLabs text-to-speech, and reads the key from the 1Password item
rowbutt elevenlabs api key. Pass line ids to render those, or --all. Add
each new file to pbx-sounds in clusters/folly/apps/pbx/kustomization.yaml;
the task names a file that is missing there. The prompts share a 700 KiB
budget, and mise run pbx:check fails if the dialplan plays a file the
ConfigMap does not carry.
Test the screen#
Place these calls after the pod rolls and the phone has fetched its profile (Change the phone).
Call line 4 from a contact's number.
Result: the handset shows
[OK] <name>and plays the Friend ring.Call line 4 from another number and press 5.
Result: the prompt plays once, then the handset shows
[5] <number>and plays the Human ring.Call line 4 from that number again and press nothing.
Result: Jonathan answers. With
PBX_TROLL_EXTENSIONset, offsite carries the call and*25on the handset has nothing to play; with it empty,*25plays the call.Dial
*29.Result: Jonathan answers and plays up the demo.
Dial
*20from each line.Result: the phone plays the echo test. A reorder tone means the line's
Dial_Planon the phone does not send*xx.Dial 933 from line 1.
Result: voip.ms reads the e911 address back.
If something goes wrong#
| Symptom | Cause | Action |
|---|---|---|
| A caller on line 4 hears "press five", talks to Jonathan, or is held in the queue or with Lenny | Line 4 screens every caller who is not a contact. | Add them as a contact, or tell them to press 5. |
Screened callers are held, never trolled, and the log has why=off | The pod started without the pbx-elevenlabs Secret, which it reads only at start. | Make sure kubectl --context folly -n pbx get externalsecret pbx-elevenlabs shows SecretSynced, then restart the pod when no call is up. |
The log has why=daily | The PBX's own cap: twenty calls today, counting each call Jonathan answers on folly and each call folly hands to offsite. | Wait for the next day. |
The log has why=CONGESTION, CHANUNAVAIL, BUSY or NOANSWER | ElevenLabs refused the call, was unreachable, or did not answer in 60 seconds. How it treats a call over its own limits is unverified; with call queueing on, it plays hold audio. | Read the agent's SIP (Diagnose a failed call). |
| A caller on line 4 gets a busy signal | Two callers are in the screen. | Wait, or raise the cap in config/inbound.conf. |
The log has kind=troll-miss site=offsite why=FAILURE-<code>, then Jonathan answers from folly | voip.ms answered the REFER, or a NOTIFY about the call to the extension, with that SIP code, and folly kept the call. | Read the REFER and its NOTIFYs (Diagnose a failed call). Check PBX_TROLL_EXTENSION against the portal and that the offsite PBX is registered. |
The log has why=FAILURE-401 or FAILURE-407 with site=offsite, and the caller is held in a sink | voip.ms challenged the REFER. Asterisk sends it again with vms-1994's credentials after Transfer() has given up, so folly holds the caller in a sink rather than dial Jonathan, and voip.ms may still move them. | Read the second REFER's answer. When voip.ms takes it, the transfer works after a challenge. |
Screened callers never reach offsite, and the log has no site=offsite | PBX_TROLL_EXTENSION is empty. | Turn on the offsite hand-off. |
The log has kind=troll site=offsite and nothing after it, the caller is dropped, and offsite logs no kind=inbound | voip.ms accepted the REFER and reported the call to the extension ringing and answered within the same second, so folly hung up, but no INVITE reached the offsite registration. This is what the extension does today. | Empty PBX_TROLL_EXTENSION, so folly dials Jonathan itself. Check the sub-account's internal extension in the portal, then place an internal call from the handset to it and watch for kind=inbound on offsite before setting it again. |
| A screened caller hears silence after the prompt, then Jonathan or a sink | voip.ms accepted the REFER, and Transfer() plays nothing while it waits for the NOTIFY that reports the call to the extension up, for up to 45 seconds. | Read the NOTIFYs. A silence ending in why=FAILURE-<code> is a call to the extension that failed, and one ending in why=timeout gets no final NOTIFY. |
pbx-contacts shows SecretSyncedError | The pbx contacts item is missing, has a repeated label, or shares its title with another item. No alert covers it. | Fix the item. The ExternalSecret retries within the hour. |
| A new contact still hears the screen | Asterisk read the contacts file at its last dialplan load, or the value is not ten digits and the template skipped it. | Run dialplan reload after the Secret has caught up. If dialplan show globals has no line for it, fix the value. |
| A removed contact still skips the screen | A reload keeps the global, or the item was deleted and its Secret kept. | Restart the pod. If the item is gone, recreate it without the field first. |
[OK] or [5] shows with the line's usual ring | The phone has not fetched the profile with Ring10 and Ring11. | Resync the phone (Change the phone). |
Related#
Linked from 3
- PBXTwo Asterisk phone switches, one on folly for the four lines of the office phone and one on offsite that hands its callers to an ElevenLabs troll agent.
- RunbooksStep-by-step procedures for the hosts, clusters, network, secrets and apps, grouped by area.
- Operate the office phoneHow the office SPA504G reaches voip.ms through the folly PBX, and how to check it, change it, and debug a call that fails.