Sign inSign up

imansur/pjsua2-call-agent

By imansur

•Updated 3 months ago

Image
0

369

imansur/pjsua2-call-agent repository overview

⁠Standalone PJSUA2 VoIP Call Agent Container

This directory contains a standalone, API-driven VoIP calling agent container built on top of PJSIP (PJSUA2) and FastAPI in Python. It is optimized to run inside headless environments (like Docker containers or remote servers) without physical audio hardware.

For a detailed step-by-step walkthrough of how this PJSIP container is compiled and built, see README_BUILD.md⁠.


⁠🚀 Features

  • PJSIP 2.14 Compilation: Compiles the standard PJSIP library and its Python SWIG bindings directly from source on the target architecture (fully supports x86_64 and arm64/Apple Silicon).
  • Null Audio Device Enabler: Automatically configures the endpoint with audDevManager().setNullDev() to prevent PJMEDIA_EAUD_NODEFDEV (Unable to find default audio device) crashes common in server environments.
  • FastAPI REST API Interface: Exposes a simple HTTP endpoint to trigger outbound SIP calls.
  • Real-time Unbuffered Logs: Configured with PYTHONUNBUFFERED=1 to ensure PJSIP signaling and Python print logs are shown immediately in Docker outputs.
  • Graceful Shut Down: Background threads monitor call states and exit cleanly without causing session termination exceptions.

⁠🛠️ Getting Started

⁠Prerequisites
  • Docker Desktop running on your machine.
⁠1. Build the Docker Image

Navigate to this directory (or run from the project root referencing this folder) and build the image:

docker build -t pjsua2-call-agent .

(Note: Compiling PJSIP from source will take 3-7 minutes during the initial build.)

⁠2. Run the Container

Start the container exposing the FastAPI server on port 8000. To play local audio files, map a folder containing your .wav files into the container:

docker run -d --name voip-agent -p 8000:8000 -v ./sounds:/app/sounds pjsua2-call-agent

⁠📞 Usage & API Reference

⁠Trigger a Call

To initiate a SIP call, send an HTTP POST request to /api/call. The call runs synchronously and returns the final call outcome in the API response after the call ends.

⁠Option A: Playing a Pre-recorded File

You can place any audio file (e.g., .mp3, .wav) in the sounds/ directory. The container will automatically standardize it to the compliant format (PCM 16-bit, 8000Hz, Mono WAV) using FFmpeg before making the call:

curl -X POST http://localhost:8000/api/call \
  -H "Content-Type: application/json" \
  -d '{
    "target_uri": "sip:[email protected]",
    "caller_id": "CustomAgent",
    "media_file_name": "announcement.mp3"
  }'
⁠Option B: Synthesizing Text-to-Speech (TTS) with IVR

If you send raw text, the container will synthesize it into natural Turkish speech using Piper TTS (Fahrettin voice) and automatically append the official voice prompt: "Alarmı tekrar dinlemek için 1'e, çağrıyı sonlandırmak için 0'a basın."

curl -X POST http://localhost:8000/api/call \
  -H "Content-Type: application/json" \
  -d '{
    "target_uri": "sip:[email protected]",
    "caller_id": "CustomAgent",
    "text": "Merhaba İlker Bey, sisteminizde kritik bir durum tespit edildi."
  }'

⁠🎛️ DTMF / IVR Interactive Behavior & Outcomes

The call executes and blocks the HTTP request until it finishes. There are the following possible outcomes returned in the API response under "result":

  1. "0 a basıldı": The recipient pressed 0 to end the call. (Returns immediately)
  2. "kullanıcı tarafından kapatıldı": The recipient hung up the phone without pressing 0. (Returns immediately)
  3. "1 e basıldı": The recipient pressed 1 at least once to replay the message (and did not end with 0). (Returns immediately)
  4. "break infinite loop": The recipient listened to the message but did not press 1 or 0. To prevent infinite looping, the container played the recording 3 times maximum and hung up. (Returns immediately)
  5. "cevap vermedi veya meşgul": The recipient did not pick up the call within 45 seconds or was busy. (Retries once after waiting 60 seconds)
  6. "error": A network, SIP, or media configuration error occurred. (Retries once after waiting 60 seconds)

⁠Response
{
  "status": "completed",
  "target": "sip:[email protected]",
  "result": "break infinite loop"
}
⁠Inspect Call States (Logs)

To watch the call progression (INVITE, ringing, answer, duration, disconnect codes):

docker logs -f voip-agent

⁠🐳 Docker Hub Publishing

To tag and upload this image to your Docker Hub repository:

  1. Log in to Docker Hub:
    docker login
    
  2. Tag the compiled image with your username:
    docker tag pjsua2-call-agent your-username/pjsua2-call-agent:latest
    
  3. Push the image to the repository:
    docker push your-username/pjsua2-call-agent:latest
    

Tag summary

Content type

Image

Digest

sha256:03ed31ce5…

Size

249.9 MB

Last updated

3 months ago

docker pull imansur/pjsua2-call-agent