feat: Calling support for both incoming and outgoing. #194
Merged
shridarpatil merged 15 commits intomainfrom Feb 25, 2026
Merged
feat: Calling support for both incoming and outgoing. #194shridarpatil merged 15 commits intomainfrom
shridarpatil merged 15 commits intomainfrom
Conversation
Owner
shridarpatil
commented
Feb 25, 2026
- Handle incoming and outgoing calls.
- IVR support for incoming calls.
- Record calls and store them on S3.
- TURN server support for UDP blocked firewall.
…ing calls Implements the full WhatsApp Business Calling API integration: - WebRTC-based voice calling with Opus codec and DTMF support - IVR flow engine with configurable menus and text-to-speech - Incoming call handling with pre-accept pattern per Meta's recommendation - Outgoing calls (agent → consumer) with dual PeerConnection bridge - Call transfers between IVR and live agents with hold music - Call permission request flow (72h validity per WhatsApp rules) - Frontend: call logs, IVR flow editor, call transfers, active call panel - CallButton integrated in chat header for agent-initiated calls
…ovements - Add Piper TTS integration for IVR greeting generation (text → OGG/Opus) - Fix outgoing calls to use contact_id instead of masked phone number - Fix WhatsApp API payloads per official Meta docs (InitiateCall, SendCallPermissionRequest) - Add call permission check via WhatsApp API before initiating outgoing calls - Handle business-initiated call status webhooks (RINGING/ACCEPTED/REJECTED) - Handle orphaned outgoing call terminate webhooks after session cleanup - Add call_permission_reply webhook processing - Fix OGG/Opus audio playback in AudioPlayer using pion oggreader - Add WebRTC UDP port range configuration (default 10000-10100) - Add TTS setup documentation to README
Replace hardcoded Google STUN server with config-driven ICE servers. Adds GET /api/calls/ice-servers endpoint so the frontend fetches server config from backend instead of hardcoding.
…e DTMF detection - Add relay_only config to force all media through TURN server - Add public_ip config for NAT 1:1 IP mapping on cloud instances - Fix OGG/Opus audio player to properly split multi-packet pages using segment table (was sending entire pages as single RTP packets) - Detect inline DTMF (telephone-event) on same m-line as audio track, since WhatsApp sends both codecs on a single track - Fix nil UUID panic in transfer WebSocket broadcast - Add 500ms stabilization delay after WebRTC connection before IVR
- Deduplicate waiting transfers by checking ID before pushing - Handle call_ended event to clean up active agent call state - Add onconnectionstatechange to peer connections to stop timer when WebRTC disconnects/fails (e.g. caller hangs up)
EndTransfer was only closing the server-side WebRTC connections without notifying WhatsApp, leaving the caller's phone still connected.
- Atomically claim transfer in DB (UPDATE WHERE status=waiting) so only one agent can accept; revert to waiting if WebRTC setup fails - Claim transfer in-memory under session mutex before releasing lock - Cap frontend ICE gathering at 3s instead of waiting indefinitely - Reduce server-side ICE gathering timeout from 15s to 5s
…improvements - Add OGG/Opus call recorder that captures both directions during bridge - Add S3 storage client for uploading recordings and generating presigned URLs - Add recording playback in call log detail dialog with mic icon indicator - Split IVR flow is_active into is_active (enabled/disabled) and is_call_start (entry point for incoming calls), with unique partial index enforcement - Add call direction and IVR flow filters to call logs - Apply phone number masking to call log endpoints - Fix missed call detection for pre-accepted incoming and unanswered outgoing calls - Block goto_flow to disabled IVR flows
…sion - Migrate CallLogsView and CallTransfersView to shared DataTable component with server-side pagination for consistent UI across all views - Add maxHeight prop to DataTable for scrollable table with fixed pagination - Add border-top and padding to DataTable pagination controls - Scope call log endpoints by permission: users without call_logs:read see only their own calls (agent_id filter), admins/managers see all - Remove call_logs:read from default agent role
… flows - Fix calling sidebar submenu collapsing by using /calling as parent path - Add phone number search to call logs with debounced input - Add consistent padding to calling view table cards - Accumulate IVR path across goto_flow transitions instead of overwriting
…alling bugs - Include digit and label in goto_flow IVR path marker so the tree shows which key was pressed to trigger a flow transition - Add IVRPathTree component with proper nested tree rendering (border-l indentation, recursive depth) replacing the flat badge list - Reuse IVR AudioPlayer across goto_flow transitions to maintain RTP sequence continuity (prevents packet drops from seq reset) - Fix toggle active/call-start wiping IVR menu by making UpdateIVRFlow only include non-zero fields in the update map - Validate TTS configuration and surface TTS errors to UI instead of silently logging them - Set agent_id on CallLog during transfer acceptance so ended webhook doesn't incorrectly mark transferred calls as missed - Re-read CallLog before deciding final status to catch late agent_id writes
0622cd0 to
10a3b91
Compare
Replace fixed waitForTimeout delays with proper element-based waits in template sending tests. Add waitForTemplatesLoaded() helper that waits for the spinner to disappear and template items to render. Fix all golangci-lint errcheck violations by handling Close/Remove return values. Apply De Morgan's law for staticcheck QF1001 and use tagged switch for QF1003.
10a3b91 to
718f028
Compare
Create a dedicated contact per test run instead of reusing contacts[0] which may have messages from a different WhatsApp account. When existing messages set selectedAccount to a mismatched account, the TemplatePicker filters by that account and returns 0 results.
Add comprehensive calling documentation covering IVR flows, call transfers, recording, WebRTC configuration, TTS setup, and network requirements. Move the TTS section from README to the docs site. Add calling to the README features list and docs sidebar.
Switch Docker base from Alpine to Debian (glibc required by Piper), download Piper binary + default English voice model during build, and install espeak-ng and opus-tools as runtime dependencies.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.