VoIP Client using Python and PJSIP.
- Python 3.9+
- PJSIP with Python bindings (pjsua2)
- Build PJSIP from source (see
docs/PJSIP.mdfor platform-specific instructions). - From the project root, run the setup script with
PJPROJECT_DIRpointing to your pjproject source:
cd /path/to/voip-client-python
PJPROJECT_DIR=/path/to/pjproject ./scripts/setup_pjsua2.shThis creates a virtual environment and installs the pjsua2 bindings.
- Activate the virtual environment (from the project root):
source .venv/bin/activateNever commit .env. Copy from .env.example and fill in real values only locally. .env is listed in .gitignore.
Logs are written to logs/, recordings to recordings/, and temporary files to tmp/; these directories are local and gitignored.
All commands below assume you are in the project root with the virtual environment activated.
voip_client/ # Main package
voip_common.py # Shared session, account, and call base (SIP/voip_*/app_*)
pjsip_common.py # PJSIP endpoint helper for pjsip_* tests (no SIP)
pjsip_test.py # PJSIP install/basic test
pjsip_test_voip.py # VoIPstudio registration test
pjsip_test_audio.py # PJSIP audio test: devices, loopback, record (no SIP)
voip_test_call.py # Test Call (#123): connect, record to recordings/, Enter to hang up
voip_echo_test.py # Echo Test (#124): hear echo, record to recordings/, optional --duration
voip_dtmf_test.py # DTMF Test (#125): send DTMF digits, then hang up
app_phone_call.py # Normal outbound call: two-way audio, record, hang up on Enter
app_echo_call.py # Echo call to any number (hear yourself)
app_ai_chatbot_call.py # Outbound call with AI ChatBot (Whisper STT + Chat Completions + TTS pipeline)
app_ai_realtime_call.py # Outbound call with AI assistant via OpenAI Realtime API (full-duplex WebSocket)
- pjsip_* – PJSIP tests (no SIP account, or registration only):
pjsip_test,pjsip_test_voip,pjsip_test_audio. Shared helper:pjsip_common.PjsipEndpoint,PjsipAudioTest. - voip_* – Provider test scripts (VoIPstudio test numbers #123, #124, #125). Use
voip_common(VoipSession, BaseVoipCall). Call classes:VoipTestCall,VoipEchoTestCall,VoipDtmfTestCall. - app_* – Application scripts (outbound calls to any number). Use
voip_common. Call classes:PhoneCall,AppEchoCall,AiChatBotCall,AiRealtimeCall.
python -m voip_client.pjsip_test- Create a local
.envfile:
cp .env.example .env- Fill in your VoIPstudio SIP credentials in
.env:
SIP_DOMAINSIP_USERNAMESIP_PASSWORD
Optional overrides:
SIP_AUTH_USERNAMESIP_TRANSPORT(udp, tcp, tls)SIP_PORTSIP_PROXYSIP_REG_TIMEOUT(seconds, default 15)SIP_TEST_CALL_EXTENSION(default 123 for Test Call)SIP_ECHO_EXTENSION(default 124 for Echo Test)SIP_DTMF_TEST_EXTENSION(default 125 for DTMF Test)
- Run the registration test:
python -m voip_client.pjsip_test_voipTest PJSIP audio: list devices, loopback (hear yourself), and save a recording. No SIP or account.
python -m voip_client.pjsip_test_audioRecordings are saved to recordings/pjsip_test_audio_YYYYMMDD_HHMMSS.wav.
Options:
--duration,-d: Test duration in seconds (default: 5)
Example with custom duration:
python -m voip_client.pjsip_test_audio --duration 30VoIPstudio provides test numbers: #123 (Test Call), #124 (Echo Test), #125 (DTMF Test). Default destinations are 123, 124, 125; override with SIP_TEST_CALL_EXTENSION, SIP_ECHO_EXTENSION, or SIP_DTMF_TEST_EXTENSION in .env or by passing a destination argument.
Test Call (#123): Call test number, connect audio, recording to recordings/, Enter to hang up.
python -m voip_client.voip_test_call [destination]Echo Test (#124): Call echo number, hear your voice echoed back, recording to recordings/, optional --duration to auto-hangup (default: 5s).
python -m voip_client.voip_echo_test [destination] [--duration SECS]DTMF Test (#125): Call DTMF test number, send a sequence of digits, then hang up.
python -m voip_client.voip_dtmf_test [destination] [--digits "1234567890#*"] [--digit-delay-ms MS]--reg-timeout: Registration timeout in seconds (default: 15) for all of the above.
Requires the same .env as the VoIPstudio registration test. Calls a phone number (or extension), connects normal two-way audio, records the conversation, and hangs up when you press Enter.
python -m voip_client.app_phone_call <phone_number>phone_number: Destination number or extension (e.g.0035123456789or an extension).- Recording saved to
recordings/app_phone_call_YYYYMMDD_HHMMSS.wav. --reg-timeout: Registration timeout in seconds (default: 15).--debug: Write event log torecordings/app_phone_call_debug_<ts>.logfor debugging.
When the call is connected, the script prints "Call connected. Press Enter to end call and save recording." Press Enter to hang up; the recording is saved automatically.
Call any number and hear yourself (mic routed to speaker). Same .env as registration test. Recording saved to recordings/app_echo_call_YYYYMMDD_HHMMSS.wav. Optional --duration to auto-hangup (default: 5s).
python -m voip_client.app_echo_call <phone_number> [--duration SECS]--duration,-d: Auto-hangup after N seconds (default: 5).--debug: Write event log torecordings/app_echo_call_debug_<ts>.logfor debugging.
Requires the same .env as the VoIPstudio registration test plus OpenAI environment variables:
OPENAI_API_KEY– your OpenAI API key (required)OPENAI_MODEL– chat model for the bot pipeline (default:gpt-4o)OPENAI_TTS_MODEL– TTS model for the bot pipeline (default:tts-1)OPENAI_TTS_VOICE– TTS voice override for the bot pipelineOPENAI_RT_MODEL– model used for Realtime audio inOpenAIRealtimeBridge(default:gpt-realtime)
These should be defined in your local .env, based on .env.example.
There are two AI call modes:
Uses a pipeline approach: caller audio is transcribed with Whisper, processed by Chat Completions, and the response is converted back to speech with OpenAI TTS. Higher latency but supports any chat model and is more cost-effective.
python -m voip_client.app_ai_chatbot_call <phone_number> [--reg-timeout SECONDS] [--system-message TEXT] [--voice VOICE_NAME] [--model MODEL] [--silence-duration MS] [--save-recordings]phone_number: Destination number or extension.--reg-timeout: Registration timeout in seconds (default: 15).--system-message: System/prompt instructions for the AI assistant.--voice: OpenAI TTS voice name (default:alloy).--model: Chat model to use (default:gpt-4o).--silence-duration: How long (ms) to wait after silence before responding (default: 1000).--save-recordings: Save call recording and transcripts torecordings/app_ai_chatbot_call_<timestamp>/(see docs/AI_Assistant.md).--debug: Write event log torecordings/app_ai_chatbot_call_debug_<ts>.logfor debugging call flow.
Uses the OpenAI Realtime API for full-duplex audio over WebSocket. Lower latency with server-side VAD for turn detection.
python -m voip_client.app_ai_realtime_call <phone_number> [--reg-timeout SECONDS] [--system-message TEXT] [--voice VOICE_NAME] [--model MODEL] [--silence-duration MS] [--save-recordings]phone_number: Destination number or extension.--reg-timeout: Registration timeout in seconds (default: 15).--system-message: System/prompt instructions for the AI assistant.--voice: OpenAI voice name (default:alloy).--model: Realtime model to use (default:gpt-realtime, override withOPENAI_RT_MODELenv).--silence-duration: How long (ms) server VAD waits after silence (default: 1000).--vad-threshold: Server VAD activation threshold, 0.0-1.0 (default: 0.5).--prefix-padding: Audio to include before detected speech, in ms (default: 300).--save-recordings: Save call recording and response WAVs torecordings/app_ai_realtime_call_<timestamp>/.--debug: Write event log torecordings/app_ai_realtime_call_debug_<ts>.logfor debugging (see docs/OpenAI_API.md).
To quickly verify that your OpenAI credentials and network connectivity work, use the small test helper:
python -m voip_client.openai_testThis script:
- Loads
OPENAI_API_KEYandOPENAI_MODEL(default:gpt-5.2) from the environment /.env - Sends a short test prompt to the chat completions API
- Prints the assistant reply or a detailed error (for example, insufficient quota)
Use this checklist to track which scripts have been manually tested after changes. Order: pjsip, then voip, then app scripts. Commands below use default options (no --debug); test scripts (pjsip_, voip__test) print trace output by default. For troubleshooting app scripts, use --debug to write event logs to recordings/.
python -m voip_client.pjsip_test– PJSIP install/basic testpython -m voip_client.pjsip_test_voip– VoIPstudio registration testpython -m voip_client.pjsip_test_audio– PJSIP audio (devices/loopback/record) testpython -m voip_client.voip_test_call [destination]– VoIPstudio Test Call (#123)python -m voip_client.voip_echo_test [destination]– VoIPstudio Echo Test (#124)python -m voip_client.voip_dtmf_test [destination]– VoIPstudio DTMF Test (#125)python -m voip_client.openai_test– OpenAI connectivity testpython -m voip_client.app_phone_call <phone_number>– Outbound phone call (two-way audio + recording)python -m voip_client.app_echo_call <phone_number>– Echo call applicationpython -m voip_client.app_ai_chatbot_call <phone_number>– Outbound call with AI ChatBot (Whisper + Chat + TTS)python -m voip_client.app_ai_realtime_call <phone_number>– Outbound call with Realtime AI assistant
Run from the project root with the virtual environment activated (see Setup above).
- docs/PJSIP.md – PJSIP overview and building the Python bindings
- docs/PJSIP_macOS.md, docs/PJSIP_Linux.md, docs/PJSIP_Windows.md – Platform-specific PJSIP install
- docs/VoIPstudio.md – VoIPstudio SIP settings and mapping to PJSIP
- docs/OpenAI_API.md – AI Assistant architecture (Whisper pipeline and Realtime API), env vars, usage
- docs/AI_Assistant.md – AI ChatBot call: recording, transcription, sample rate, testing