mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2026-10-04 02:04:12 +00:00
Applications currently have no way to observe a mid-call hold/un-hold.
The feature-server handles the in-dialog re-INVITE internally (re-modifies
the endpoint, returns 200) but never notifies the app, so a transcription
or agent-assist app can't pause/resume when a caller is held or retrieved.
This detects the hold state transition on a re-INVITE and delivers it over
the existing sipRequestWithinDialogHook channel as a verb:hook, plus emits
a local 'hold'/'unhold' event so in-process tasks (e.g. transcribe) can react.
- call-session.js: ordinary calls — reuse isOnhold() (a=sendonly/a=inactive).
- siprec-call-session.js: SIPREC overrides _onReinvite, so a separate handler
is required. SIPREC recording streams are sendonly by nature, so a stream
flipping to a=inactive is treated as the hold signal; the full multipart
body (SDP + rs-metadata) is always forwarded. Fires on transition only;
other re-INVITEs are delivered as event:"reinvite".
Delivery uses requestor.request('verb:hook', ...) — the same channel
_handleRefer uses — rather than a task-bound performHook, so events are not
dropped if the current task has ended. Enable per call with:
{"verb":"config","sipRequestWithinDialogHook":"/hold-events"}
Confirmed live against Cisco CUBE (Cisco-SIPGateway/IOS-17.12.7b) over SIPREC:
both recording streams flip sendonly<->inactive on hold/resume, each
transition emitted correctly.
The whole feature is opt-in behind the JAMBONES_HOLD_UNHOLD_EVENTS env var;
when it is unset, _notifyHoldState / _notifySipRecReinvite are no-ops (neither
the local event nor the hook fires).
Reinstates the feature previously reverted in #1563. The revert was due to the
unit test failing in the full suite: lib/config.js captures the env var once at
load time, and earlier suite files require config/session modules (flag unset)
before this test could set it, so the enabled-path assertions saw a disabled
feature. The test now force-reloads config + the session modules with the flag
set (and restores the module cache afterward), so it is robust to suite load order.
99 lines
4.8 KiB
Markdown
99 lines
4.8 KiB
Markdown
# jambonz-feature-server [](https://github.com/jambonz/jambonz-feature-server/actions/workflows/build.yml)
|
|
|
|
This application implements the core feature server of the jambones platform.
|
|
|
|
> Note: If you are a developer looking to work on the code please read our [how-to for that](./docs/contributing.md).
|
|
|
|
## Configuration
|
|
|
|
Configuration is provided via environment variables:
|
|
|
|
| variable | meaning | required?|
|
|
|----------|----------|---------|
|
|
|AWS_ACCESS_KEY_ID| aws access key id, used for TTS/STT as well SNS notifications|no|
|
|
|AWS_REGION| aws region| no|
|
|
|AWS_SECRET_ACCESS_KEY| aws secret access key, used per above|no|
|
|
|AWS_SNS_TOPIC_ARN| aws sns topic arn that scale-in lifecycle notifications will be published to|no|
|
|
|DRACHTIO_HOST| ip address of drachtio server (typically '127.0.0.1')|yes|
|
|
|DRACHTIO_PORT| listening port of drachtio server for control connections (typically 9022)|yes|
|
|
|DRACHTIO_SECRET| shared secret|yes|
|
|
|ENABLE_METRICS| if 1, metrics will be generated|no|
|
|
|ENCRYPTION_SECRET| secret for credential encryption(JWT_SECRET is deprecated) |yes|
|
|
|GOOGLE_APPLICATION_CREDENTIALS| path to gcp service key file|yes|
|
|
|HTTP_PORT| tcp port to listen on for API requests from jambonz-api-server|yes|
|
|
|HTTP_IP| IP Address for API requests from jambonz-api-server |no|
|
|
|JAMBONES_GATHER_EARLY_HINTS_MATCH| if true and hints are provided, gather will opportunistically review interim transcripts if possible to reduce ASR latency |no|
|
|
|JAMBONES_FREESWITCH| IP:port:secret for Freeswitch server (e.g. '127.0.0.1:8021:JambonzR0ck$'|yes|
|
|
|JAMBONES_HOLD_UNHOLD_EVENTS| if set, surface in-dialog hold/un-hold: emits a 'hold'/'unhold' event and, when sipRequestWithinDialogHook is configured, delivers it to the application. Disabled when unset|no|
|
|
|JAMBONES_LOGLEVEL| log level for application, 'info' or 'debug'|no|
|
|
|JAMBONES_MYSQL_HOST| mysql host|yes|
|
|
|JAMBONES_MYSQL_USER| mysql username|yes|
|
|
|JAMBONES_MYSQL_PASSWORD| mysql password|yes|
|
|
|JAMBONES_MYSQL_DATABASE| mysql data|yes|
|
|
|JAMBONES_MYSQL_CONNECTION_LIMIT| mysql connection limit |no|
|
|
|JAMBONES_NETWORK_CIDR| CIDR of private network that feature server is running in (e.g. '172.31.0.0/16')|yes|
|
|
|JAMBONES_REDIS_HOST| redis host|yes|
|
|
|JAMBONES_REDIS_PORT|redis port|yes|
|
|
|JAMBONES_SBCS| list of IP addresses (on the internal network) of SBCs, comma-separated|yes|
|
|
|STATS_HOST| ip address of metrics host (usually '127.0.0.1' since telegraf is installed locally|no|
|
|
|STATS_PORT| listening port for metrics host|no|
|
|
|STATS_PROTOCOL| 'tcp' or 'udp'|no|
|
|
|STATS_TELEGRAF| if 1, metrics will be generated in telegraf format|no|
|
|
|JAMBONZ_RECORD_WS_BASE_URL| recording websocket URL to send the recording audio|no|
|
|
|JAMBONZ_RECORD_WS_USERNAME| recording websocket username|no|
|
|
|JAMBONZ_RECORD_WS_PASSWORD| recording websocket password|no|
|
|
|ANCHOR_MEDIA_ALWAYS| keep media on media server|no|
|
|
|JAMBONZ_DISABLE_DIAL_PAI_HEADER| control P-Asserted-Identity header on B-Leg|no|
|
|
|
|
### running under pm2
|
|
Typically, this application runs under [pm2](https://pm2.io) using an [ecosystem.config.js](https://pm2.keymetrics.io/docs/usage/application-declaration/) file similar to this:
|
|
```js
|
|
module.exports = {
|
|
apps : [
|
|
{
|
|
name: 'jambonz-feature-server',
|
|
cwd: '/home/admin/apps/jambonz-feature-server',
|
|
script: 'app.js',
|
|
instance_var: 'INSTANCE_ID',
|
|
out_file: '/home/admin/.pm2/logs/jambonz-feature-server.log',
|
|
err_file: '/home/admin/.pm2/logs/jambonz-feature-server.log',
|
|
exec_mode: 'fork',
|
|
instances: 1,
|
|
autorestart: true,
|
|
watch: false,
|
|
max_memory_restart: '1G',
|
|
env: {
|
|
NODE_ENV: 'production',
|
|
GOOGLE_APPLICATION_CREDENTIALS: '/home/admin/credentials/gcp.json',
|
|
AWS_ACCESS_KEY_ID: 'XXXXXXXXXXXX',
|
|
AWS_SECRET_ACCESS_KEY: 'YYYYYYYYYYYYYYYYYYYYY',
|
|
AWS_REGION: 'us-west-1',
|
|
ENABLE_METRICS: 1,
|
|
STATS_HOST: '127.0.0.1',
|
|
STATS_PORT: 8125,
|
|
STATS_PROTOCOL: 'tcp',
|
|
STATS_TELEGRAF: 1,
|
|
AWS_SNS_TOPIC_ARN: 'arn:aws:sns:us-west-1:xxxxxxxxxxx:terraform-20201107200347128600000002',
|
|
JAMBONES_NETWORK_CIDR: '172.31.0.0/16',
|
|
JAMBONES_MYSQL_HOST: 'aurora-cluster-jambonz.cluster-yyyyyyyyyyy.us-west-1.rds.amazonaws.com',
|
|
JAMBONES_MYSQL_USER: 'admin',
|
|
JAMBONES_MYSQL_PASSWORD: 'foobarbz',
|
|
JAMBONES_MYSQL_DATABASE: 'jambones',
|
|
JAMBONES_MYSQL_CONNECTION_LIMIT: 10,
|
|
JAMBONES_REDIS_HOST: 'jambonz.zzzzzzz.0001.usw1.cache.amazonaws.com',
|
|
JAMBONES_REDIS_PORT: 6379,
|
|
JAMBONES_LOGLEVEL: 'debug',
|
|
HTTP_PORT: 3000,
|
|
DRACHTIO_HOST: '127.0.0.1',
|
|
DRACHTIO_PORT: 9022,
|
|
DRACHTIO_SECRET: 'sharedsecret',
|
|
JAMBONES_SBCS: '172.31.32.10',
|
|
JAMBONES_FREESWITCH: '127.0.0.1:8021:sharedsecret'
|
|
}
|
|
}]
|
|
};
|
|
```
|
|
|
|
#### Running the test suite
|
|
|
|
Please [see this](./docs/contributing.md#run-the-regression-test-suite). |