Skip to main content

A lightweight Python-based SIP client with voice support

Project description

uSIP - Lightweight Python SIP Client

Python Version License Build Status Coverage

A lightweight Python-based SIP client with full voice support, designed for professional VoIP applications.

Features

  • ๐ŸŽฏ Full SIP Protocol Support: Registration, calls, messaging, presence
  • ๐Ÿ”Š Voice Communication: Real-time audio streaming with RTP
  • ๐ŸŽง Audio Device Management: List, select, and switch audio devices dynamically
  • ๐Ÿ“ฑ Event-Driven Architecture: Comprehensive callback system for all SIP events
  • ๐Ÿ“Š Call Management: Multiple concurrent calls, call history, statistics
  • ๐ŸŽ›๏ธ Flexible Audio: Runtime device switching, audio preferences
  • ๐Ÿ”„ Automatic Session Management: Keep-alive, re-registration, session refresh

Installation

From PyPI (Recommended)

pip install uSIP

From Source

git clone https://github.com/Dashhhhhhhh/uSIP.git
cd uSIP
pip install -e .

Development Installation

git clone https://github.com/Dashhhhhhhh/uSIP.git
cd uSIP
pip install -e ".[dev]"

Requirements

  • Python 3.8+
  • PyAudio (for audio functionality)
  • python-dotenv (for configuration)
  • rich (for enhanced console output)

System Dependencies

Ubuntu/Debian

sudo apt-get install portaudio19-dev

macOS

brew install portaudio

Windows

PyAudio wheels are available for Windows, no additional setup required.

Quick Start

Basic Usage

from sip_client import SIPClient, SIPAccount

# Create SIP account
account = SIPAccount(
    username="your_username",
    password="your_password",
    domain="your_sip_provider.com"
)

# Create and start client
client = SIPClient(account)
client.start()

# Register with server
client.register()

# Make a call
call_id = client.make_call("1234567890")

# Clean up
client.stop()

Using Environment Variables

Create a .env file:

SIP_USERNAME=your_username
SIP_PASSWORD=your_password
SIP_DOMAIN=your_sip_provider.com
SIP_PORT=5060
from sip_client import SIPClient

# Client will automatically load from environment
client = SIPClient()
client.start()
client.register()

Event Handling

from sip_client import SIPClient, CallState, RegistrationState

client = SIPClient()

# Set up event callbacks
def on_registration_state(state: RegistrationState):
    print(f"Registration: {state.value}")

def on_incoming_call(call_info):
    print(f"Incoming call from {call_info.remote_uri}")
    client.answer_call(call_info.call_id)

def on_call_state(call_info):
    print(f"Call {call_info.call_id}: {call_info.state.value}")

# Register callbacks
client.on_registration_state = on_registration_state
client.on_incoming_call = on_incoming_call
client.on_call_state = on_call_state

client.start()
client.register()

API Reference

SIPClient

The main client class providing all SIP functionality.

Core Methods

  • start() - Start the SIP client
  • stop() - Stop the client and clean up resources
  • register() - Register with SIP server
  • unregister() - Unregister from SIP server

Call Management

  • make_call(target_uri, input_device=None, output_device=None) - Make outgoing call
  • answer_call(call_id, input_device=None, output_device=None) - Answer incoming call
  • hangup(call_id) - End a call
  • get_calls() - Get list of active calls
  • get_call(call_id) - Get specific call information

Audio Management

  • get_audio_devices() - List available audio devices
  • switch_audio_device(call_id, input_device=None, output_device=None) - Switch devices during call

Event Callbacks

  • on_registration_state - Registration state changes
  • on_incoming_call - Incoming call notifications
  • on_call_state - Call state changes
  • on_call_media - Media events
  • on_message - SIP message events

Data Models

SIPAccount

@dataclass
class SIPAccount:
    username: str
    password: str
    domain: str
    port: int = 5060
    display_name: Optional[str] = None

CallInfo

@dataclass
class CallInfo:
    call_id: str
    local_uri: str
    remote_uri: str
    state: CallState
    direction: str  # "incoming" or "outgoing"
    start_time: Optional[float] = None
    answer_time: Optional[float] = None
    end_time: Optional[float] = None
    
    @property
    def duration(self) -> float:
        # Returns call duration in seconds

AudioDevice

@dataclass
class AudioDevice:
    index: int
    name: str
    max_input_channels: int
    max_output_channels: int
    default_sample_rate: float
    
    @property
    def is_input(self) -> bool
    
    @property
    def is_output(self) -> bool

Enums

CallState

  • IDLE - No active call
  • CALLING - Outgoing call initiated
  • RINGING - Call is ringing
  • CONNECTED - Call is active
  • DISCONNECTED - Call ended normally
  • BUSY - Remote party is busy
  • FAILED - Call failed

RegistrationState

  • UNREGISTERED - Not registered
  • REGISTERING - Registration in progress
  • REGISTERED - Successfully registered
  • FAILED - Registration failed

Examples

Basic Call Example

from sip_client import SIPClient, SIPAccount, CallState

account = SIPAccount(
    username="user",
    password="pass",
    domain="provider.com"
)

client = SIPClient(account)
client.start()
client.register()

# Make a call
call_id = client.make_call("1234567890")

# Wait for call to connect
import time
time.sleep(5)

# Check call status
call = client.get_call(call_id)
if call and call.state == CallState.CONNECTED:
    print(f"Call connected! Duration: {call.duration:.2f}s")
    
    # End call after 10 seconds
    time.sleep(10)
    client.hangup(call_id)

client.stop()

Audio Device Management

from sip_client import SIPClient

client = SIPClient()
client.start()

# List available audio devices
devices = client.get_audio_devices()
for device in devices:
    print(f"{device.index}: {device.name} ({'INPUT' if device.is_input else ''} {'OUTPUT' if device.is_output else ''})")

# Make call with specific devices
call_id = client.make_call("1234567890", input_device=1, output_device=2)

# Switch devices during call
client.switch_audio_device(call_id, input_device=3, output_device=4)

client.stop()

Multiple Concurrent Calls

from sip_client import SIPClient

client = SIPClient()
client.start()
client.register()

# Make multiple calls
call1 = client.make_call("1234567890")
call2 = client.make_call("0987654321")

# Manage calls independently
calls = client.get_calls()
for call in calls:
    print(f"Call {call.call_id}: {call.remote_uri} ({call.state.value})")

# End specific call
client.hangup(call1)

client.stop()

Architecture

The library follows a modular architecture:

sip_client/
โ”œโ”€โ”€ __init__.py          # Public API
โ”œโ”€โ”€ client.py            # Main SIP client
โ”œโ”€โ”€ models/              # Data models
โ”‚   โ”œโ”€โ”€ account.py       # SIP account
โ”‚   โ”œโ”€โ”€ call.py          # Call information
โ”‚   โ””โ”€โ”€ enums.py         # State enumerations
โ”œโ”€โ”€ audio/               # Audio management
โ”‚   โ”œโ”€โ”€ manager.py       # Audio streaming
โ”‚   โ””โ”€โ”€ devices.py       # Device management
โ”œโ”€โ”€ sip/                 # SIP protocol
โ”‚   โ”œโ”€โ”€ protocol.py      # Core protocol
โ”‚   โ”œโ”€โ”€ messages.py      # Message handling
โ”‚   โ””โ”€โ”€ authentication.py # Authentication
โ””โ”€โ”€ utils/               # Utilities
    โ””โ”€โ”€ helpers.py       # Helper functions

Testing

Run the test suite:

# Run all tests
pytest

# Run with coverage
pytest --cov=sip_client

# Run specific test categories
pytest -m unit          # Unit tests only
pytest -m integration   # Integration tests only
pytest -m "not audio"   # Skip audio tests

Development

Setting up Development Environment

git clone https://github.com/Dashhhhhhhh/uSIP.git
cd uSIP
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -e ".[dev]"

Code Quality

# Format code
black src tests examples

# Sort imports
isort src tests examples

# Type checking
mypy src

# Linting
flake8 src tests examples

# Run all quality checks
pre-commit run --all-files

Running Examples

# Basic usage
python examples/basic_usage.py

# Advanced features
python examples/advanced_usage.py

Performance

  • Memory Usage: ~10MB baseline, ~5MB per active call
  • CPU Usage: <5% during calls on modern hardware
  • Latency: <50ms audio latency with proper audio device configuration
  • Concurrent Calls: Supports 50+ concurrent calls (limited by system resources)

Troubleshooting

Common Issues

  1. PyAudio Installation Problems

    # Ubuntu/Debian
    sudo apt-get install portaudio19-dev
    pip install pyaudio
    
    # macOS
    brew install portaudio
    pip install pyaudio
    
  2. Audio Device Issues

    # List available devices
    devices = client.get_audio_devices()
    for device in devices:
        print(f"{device.index}: {device.name}")
    
  3. Registration Issues

    • Check SIP credentials
    • Verify network connectivity
    • Ensure SIP server is accessible
    • Check firewall settings (UDP port 5060)
  4. Call Issues

    • Verify registration status
    • Check audio device availability
    • Ensure RTP ports are not blocked (UDP 10000+)

Debug Logging

import logging
logging.basicConfig(level=logging.DEBUG)

# Enable SIP message logging
client = SIPClient()
client.on_message = lambda msg, addr: print(f"SIP: {msg}")

Contributing

We welcome contributions! Please see CONTRIBUTING.md for details.

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • Built on top of the Session Initiation Protocol (RFC 3261)
  • Audio functionality powered by PyAudio
  • Inspired by PJSIP and other professional SIP libraries
  • Thanks to all contributors and testers

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

usip-1.0.0.tar.gz (34.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

usip-1.0.0-py3-none-any.whl (36.2 kB view details)

Uploaded Python 3

File details

Details for the file usip-1.0.0.tar.gz.

File metadata

  • Download URL: usip-1.0.0.tar.gz
  • Upload date:
  • Size: 34.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.0

File hashes

Hashes for usip-1.0.0.tar.gz
Algorithm Hash digest
SHA256 9ca498c0f99a667c4593bf24b4a7e8f2696824222c1b8b9395fc073f056f534f
MD5 7d6bf7a1cfc90fcc50d8d727abb0b031
BLAKE2b-256 09d09497959b692869f2a82c42855a462727ce1dacf39f73dc05d48cbcc426be

See more details on using hashes here.

File details

Details for the file usip-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: usip-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 36.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.0

File hashes

Hashes for usip-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c9281b77f4d1aa1f412e1aea5654e08f9c1993559c2e560fb3eaa16f04335e57
MD5 25d08dc4e5fd8aa29c548d323131deba
BLAKE2b-256 8fe7ec7584990e18726cb5723fe27c1082fcc9a876154cf5010324a42d9f53b3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page