mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2026-07-24 05:02:20 +00:00
9973670a6c
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.
4.8 KiB
4.8 KiB
jambonz-feature-server 
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.
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 using an ecosystem.config.js file similar to this:
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.