Skip to content

An open-source Python library for easy VoIP call integration using SIP and SDP protocols. Simplify real-time communication and audio handling in your applications.

License

Notifications You must be signed in to change notification settings

moha-abdi/PySIP

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PySIP Logo

Python SIP Library for Custom VoIP Solutions

PySIP is an asynchronous Python library designed to simplify working with the Session Initiation Protocol (SIP) for VoIP communication. Whether you're building automated call systems, interactive voice response (IVR) menus, or any SIP-based application, PySIP gives you the flexibility to create and manage SIP accounts, handle calls, and implement custom logic with ease.

Features

Feature Description
Complete SIP Account Management Easily create, register, and manage SIP accounts.
Custom Call Flows Write scripts to automate call flows with your own business logic.
UDP Transport Layer Asynchronous, efficient UDP transport for sending and receiving SIP messages.
Flexible Call Handling Handle incoming and outgoing SIP calls, play messages, and gather user input.
Fully Extensible Includes an example bot for appointment booking, but you can easily write any SIP-based automation you need.

📚 Table of Contents

  1. Installation
  2. Project Structure
  3. Getting Started
  4. Detailed Usage
  5. Example Script
  6. Creating Your Custom SIP Scripts
  7. Contributing

🚀 Installation

Option 1: Install from PyPI

You can install PySIP directly from PyPI using pip:

pip install PySIPio

Caution

Note that the package name on PyPI is PySIPio and not PySIP

Option 2: Install from source

Step 1: Clone the repository

git clone https://github.com/moha-abdi/PySIP.git
cd PySIP

Step 2: Install dependencies

Ensure you have Python 3.8+ installed. Install the required dependencies using:

pip install -r requirements.txt

📁 Project Structure

The project is structured to provide a clean separation between the core SIP library and any custom scripts you want to write. Here's an overview of the project layout:

PySIP/
│
├── PySIP/                     # Core library files
│   ├── sip_account.py          # SIP account management
│   ├── sip_core.py             # SIP message parsing and handling
│   ├── udp_handler.py          # Asynchronous UDP transport for SIP
│
├── scripts/                    # Example custom scripts
│   └── appointment_booking_bot.py  # Example bot for appointment booking
│
├── test.py                     # Example usage of PySIP for testing
├── requirements.txt            # Project dependencies
├── .env.example                # Example environment configuration
└── README.md                   # Project documentation

🏁 Getting Started

Step 1: Environment Setup

Create a .env file in your working directory to store your SIP account credentials and server details:

SIP_USERNAME=your_sip_username
SIP_PASSWORD=your_sip_password
SIP_SERVER=your_sip_server

Step 2: Setting Up a SIP Account

A SIP account is essential for handling calls. To start, you need to create an instance of the SipAccount class, which requires your SIP credentials (username, password, and server). Here's how to do it:

from PySIP.sip_account import SipAccount
import os
from dotenv import load_dotenv

# Load SIP credentials from .env file
load_dotenv()

account = SipAccount(
    os.environ["SIP_USERNAME"],
    os.environ["SIP_PASSWORD"],
    os.environ["SIP_SERVER"],
)

Step 3: Registering the Account

Once the SipAccount is created, the next step is to register it with the SIP server:

await account.register()

This sends a SIP REGISTER request to the server to activate the account. Once registered, you can make calls or listen for incoming calls.


📘 Detailed Usage

SIP Account

The SipAccount class is at the core of PySIP. It handles all account-related tasks such as registration, making calls, and unregistering from the SIP server.

Instantiating a SIP Account:

account = SipAccount(username, password, server)

Registering:

Call the register() method to register the SIP account with the server:

await account.register()

Making Calls:

The make_call(destination) method initiates a call to the destination number:

call = account.make_call("destination_number")

Handling Incoming Calls:

Use the on_incoming_call decorator to define a function that will handle incoming calls:

@account.on_incoming_call
async def handle_incoming_call(call: SipCall):
    await call.accept()  # or call.reject() or call.busy()
    await call.call_handler.say("Thank you for calling us!")
    await call.call_handler.hangup()

Unregistering:

When you're done, unregister the account to gracefully close the session:

await account.unregister()

Call Handling

The CallHandler is responsible for handling the call flow. It allows you to say messages, gather input from the caller, or transfer the call.

Playing a message to the caller:

await call_handler.say("Welcome to our service.")

Gathering user input:

Use gather() to gather input from the user, such as pressing a digit:

dtmf_key = await call_handler.gather(length=1, timeout=5)

Transferring the call:

You can forward the call to another number:

await call_handler.transfer_to("1234567890")

Accepting, Rejecting, or Setting Busy for Incoming Calls:

For incoming calls, you can use the following methods:

await call.accept()  # Accept the incoming call
await call.reject()  # Reject the incoming call
await call.busy()    # Mark the line as busy for the incoming call

UDP Transport

The UdpHandler is an internal module that manages the asynchronous sending and receiving of SIP messages over the network.

Sending a message:

The send_message() method sends a UDP message to the SIP server or peer:

self.transport.sendto(message)

Receiving a datagram:

The datagram_received() method handles incoming messages, placing them in a queue for processing:

self.data_q.put_nowait(data)

🔍 Example Script

To demonstrate PySIP in action, we've provided a basic example of an appointment booking bot. This bot allows callers to book appointments via a phone call.

import asyncio
from PySIP.sip_account import SipAccount
from scripts.appointment_booking_bot import appointment_booking_bot
from dotenv import load_dotenv
import os

# Load environment variables
load_dotenv()

# Initialize SIP account with credentials from .env file
account = SipAccount(
    os.environ["SIP_USERNAME"],
    os.environ["SIP_PASSWORD"],
    os.environ["SIP_SERVER"],
)

@account.on_incoming_call
async def handle_incoming_call(call: SipCall):
    await call.accept()
    await call.call_handler.say("We have received your call successfully")

async def main():
    # Register the SIP account
    await account.register()

    # Make a call to a test number (e.g., '111')
    call = account.make_call("111")
    call_task = asyncio.create_task(call.start())

    # Run the appointment booking bot
    await appointment_booking_bot(call.call_handler, customer_name="John")

    # Wait for the call to complete, then unregister
    await call_task
    await account.unregister()

if __name__ == "__main__":
    asyncio.run(main())

🛠 Creating Your Custom SIP Scripts

While the appointment booking bot is just one example, PySIP is designed to let you create any SIP-based automation or custom script that fits your needs.

To create your own script:

  1. Create a Python file in the scripts/ directory.
  2. Write your custom call logic using the CallHandler class to control the call flow.
  3. Use the SipAccount to register and make calls as demonstrated in the example script.

🤝 Contributing

Contributions are welcome! If you would like to contribute to the development of PySIP, feel free to open issues or submit pull requests.


Made with ❤️ by Moha Abdi