* fix: carry siprec recording state across a feature server transfer
transferCallToFeatureServer() stored the application, callInfo and remaining tasks,
but not the SIPREC recording state, so the receiving session started at
RecordingOff while the SBC was still recording. From there every live call control
on the recording was rejected locally before an INFO was ever sent: stop and pause
fail the guards in notifyRecordOptions, and a fresh startCallRecording is refused
by the SBC as a duplicate.
Carry recordOptions and the record state through the transfer and restore both on
the receiving session, which also keeps propagateAnswer from issuing a second
startCallRecording for a call that is already being recorded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: add standalone smoke test for siprec across a feature server transfer
Drives the failing flow end to end - answer, start SIPREC, enqueue, create the
agent call on a different feature server, dequeue by callSid - while acting as
the SIPREC recorder, so it can tell whether the recording kept receiving media
across the REFER and whether it was BYEd when the call ended.
Needs two or more feature servers and a real inbound call, so it lives outside
the mocha suite and is run by hand; npm test does not pick it up.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: let the siprec smoke test originate both call legs itself
Waiting for a human to dial in with music playing made the test hard to run and
easy to make meaningless (a muted caller sends no RTP, so "the recording is
silent" proves nothing). Add a built-in SIP endpoint that answers and streams a
PCMU tone, and have the test place both legs through createCall, so a run needs
only an account_sid and no carrier, DID or softphone.
That makes the default mode exercise the transfer path in sbc-outbound; the
previous flow is kept as SMOKE_MODE=inbound for the sbc-inbound path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: hand the inherited recording state to one session only
Review of the previous commit turned up two ways the carried state leaks, both
because it was read off the shared application object and left there:
- a call transferred twice kept a stale siprecRecording from the first hop.
transferCallToFeatureServer copies cs.application, and the new guard only
wrote the key, so a call recorded FS1->FS2, stopped there, then moved to FS3
arrived believing it was still recording: startCallRecording rejected as
"already started", stopCallRecording sent an INFO for a session that was
gone.
- child legs got it too. dial passes cs.application straight to
ConfirmCallSession and place-outdial spreads it for the adulting session, so
those sessions came up with recordState=recording_on and the parent's SRS
options while their own dialog had no siprec session at all.
The transferred session now takes the state off the application as it adopts it,
so exactly one session owns it.
Also fixes the smoke test's silence measurement, which was computed per stream
and reported a whole quiet window as a gap - a legitimately silent second stream
failed the run - and splits the README's requirements by mode, since the default
rest mode needs no portal application and no external caller.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: drop the standalone smoke script, the harness test covers it
smoke-tests/siprec-fs-transfer was a self-contained driver for the cross-feature
-server SIPREC flow, written before the same scenario landed in the smoke-tester
harness as TestVerb_Siprec_SurvivesFeatureServerTransfer (plus a REST-leg
variant for the sbc-outbound path). The harness version is the one that runs in
CI, asserts the recorded audio with Deepgram rather than counting packets, and
is what proved both fixes on a real cluster - keeping a second implementation of
the same flow here only invites the two to drift.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* deepgram gather: if both endpointing and utterance_end_ms are set (but not continous asr) return either when we get speech_final or UtteranceEnd. This is the belt-and-suspenders apprach deepgram is recommending
* include verb id in action hook if one was provided in the verb set
* minor
* update to fsmrf with fix
* changes to support elevenlabs tts streaming
* say: add vendor data to span
* bug: tts spans must include cached property
* add env for JAMBONES_USE_FREESWITCH_TIMER_FD
* fix bug in prev commit
* wip
* linting
* wip - caching files generating by streaming tts
* wip caching
* cleanup some logs
* handle tts streaming failure, write alert
* update node version dependency
* set timerfd on outbound call scenarios
* default model to nova-2-phonecall when using deepgram
---------
Co-authored-by: Dave Horton <daveh@beachdognet.com>
* verbhook on ws connection should be ended in next redirect command
* wip
* wip
* minor change for readability
---------
Co-authored-by: Dave Horton <daveh@beachdognet.com>
* initial changes for amd
* wip
* fix bug where transcripts were discarded
* a bit of refactoring, and adding support for avmd in config verb
* bug fixes
* add b3 header for trace propagation on initial webhook
* logging
* add tracing context to all webhooks
* Add span parameter to Task.getTracingPropagation. Pass proper span to getTracingPropagation calls in Task methods to propagate the proper spanId (#91)
* some tracing cleanup
* bugfix: azure stt results need to be ordered by confidence level before processing (#92)
* fix assertion
* bugfix: vad was not enabled on config verb, restart STT on empty transcript in gather
* gather: dont send webhook if call is gone
* rest outdial: handle 302 redirect so we can later cancel request if needed (#95)
* gather: restart if we get an empty transcript (looking at you, Azure)
Co-authored-by: javibookline <98887695+javibookline@users.noreply.github.com>
* initial adds for otel tracing
* initial basic testing
* basic tracing for incoming calls
* linting
* add traceId to the webhook params
* trace webhook calls
* tracing: add new commands as tags when receiving async commands over websocket
* tracing new commands
* add summary for config verb
* trace async commands
* bugfix: undefined ref
* tracing: give time for final webhooks before closing root span
* tracing bugfix: span for background gather was not ended
* tracing - minor tag changes
* tracing - add span atttribute for reason call ended
* trace call status webhooks, add app version to trace output
* config: add support for automatically re-enabling
* env var to customize service name in tracing UI
* config: change to use 'sticky' attribute to re-enable bargein automatically
* fix warnings
* when adulting create a new root span
* when background gather triggers bargein via vad clear queue of tasks
* additional trace attributes for dial and refer
* fix dial tracing
* add better summary for dial
* fix prev commit
* add exponential backoff to WsRequestor reconnection logic
* add calling number to log metadata, as this will be frequently the key data given for troubleshooting
* add accountSid to log metadata
* make handshake timeout for ws connections configurable with default 1.5 secs
* rename env var
* fix bug prev checkin
* logging fixes
* consistent env naming
* add bargein support to gather
* bugfix: gather handles interim results from azure
* gather: support for min/max digits and interdigit timeout
* add task summary to some log messages
* logging improvements