Metadata-Version: 2.4
Name: uSIP
Version: 1.0.0
Summary: A lightweight Python-based SIP client with voice support
Author-email: uSIP Development Team <support@usip.dev>
Maintainer-email: uSIP Development Team <support@usip.dev>
License: MIT
Project-URL: Homepage, https://github.com/Dashhhhhhhh/uSIP
Project-URL: Documentation, https://sip-client-library.readthedocs.io/
Project-URL: Repository, https://github.com/Dashhhhhhhh/uSIP.git
Project-URL: Issues, https://github.com/Dashhhhhhhh/uSIP/issues
Project-URL: Changelog, https://github.com/Dashhhhhhhh/uSIP/blob/main/CHANGELOG.md
Keywords: sip,voip,audio,telecommunications,rtp,telephony
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Communications :: Telephony
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: pyaudio>=0.2.11
Requires-Dist: python-dotenv>=0.19.0
Requires-Dist: rich>=12.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
Requires-Dist: black>=22.0.0; extra == "dev"
Requires-Dist: isort>=5.10.0; extra == "dev"
Requires-Dist: flake8>=4.0.0; extra == "dev"
Requires-Dist: mypy>=0.950; extra == "dev"
Requires-Dist: pre-commit>=2.17.0; extra == "dev"
Provides-Extra: examples
Requires-Dist: click>=8.0.0; extra == "examples"

# uSIP - Lightweight Python SIP Client

[![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![Build Status](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/Dashhhhhhhh/uSIP)
[![Coverage](https://img.shields.io/badge/coverage-71%25-brightgreen.svg)](https://github.com/Dashhhhhhhh/uSIP)

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)

```bash
pip install uSIP
```

### From Source

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

### Development Installation

```bash
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
```bash
sudo apt-get install portaudio19-dev
```

#### macOS
```bash
brew install portaudio
```

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

## Quick Start

### Basic Usage

```python
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:
```env
SIP_USERNAME=your_username
SIP_PASSWORD=your_password
SIP_DOMAIN=your_sip_provider.com
SIP_PORT=5060
```

```python
from sip_client import SIPClient

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

### Event Handling

```python
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
```python
@dataclass
class SIPAccount:
    username: str
    password: str
    domain: str
    port: int = 5060
    display_name: Optional[str] = None
```

#### CallInfo
```python
@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
```python
@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

```python
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

```python
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

```python
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:

```bash
# 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

```bash
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

```bash
# 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

```bash
# 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**
   ```bash
   # Ubuntu/Debian
   sudo apt-get install portaudio19-dev
   pip install pyaudio
   
   # macOS
   brew install portaudio
   pip install pyaudio
   ```

2. **Audio Device Issues**
   ```python
   # 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

```python
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](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](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
