Skip to main content

Pure-Python SIP/RTP user-agent library (UAC + UAS) with asyncio

Project description

opensip

PyPI Python License Status

Saf-Python, asyncio tabanlı SIP/RTP user-agent kütüphanesi. UAC + UAS, REGISTER, HTTP Digest auth, G.711 ses kodek'i, opsiyonel mikrofon/hoparlör köprüsü — sıfır C bağımlılığı, ~33 KB wheel.

pip install opensip          # sinyalleşme + RTP (numpy varsa hızlandırma)
pip install "opensip[audio]" # + mic/speaker köprüsü (sounddevice + numpy)

⚠️ Erken alfa. Gerçek bir Türk bulut-PBX provider'ı (netsantral.com) üzerinden uçtan uca iki yönlü ses ile doğrulandı. Yine de RFC 3261'in birkaç önemli parçası eksik — production'a almadan önce Bilinen sınırlamalar bölümünü okuyun.

Özellikler

  • 🎯 Saf Python, sıfır C bağımlılığı (audio extra hariç)
  • asyncio — tek event loop'ta binlerce eşzamanlı dialog
  • 📞 UAC + UAS — hem arama yap hem de cevap ver
  • 🔐 HTTP Digest auth — MD5, MD5-sess, SHA-256, qop=auth (RFC 7616)
  • 🎙️ G.711 PCMU/PCMA — numpy varsa vektörize, 20 ms frame başına ~1 µs
  • 🔄 OPTIONS keepalive — provider'ın "alive?" pingini otomatik 200 OK
  • 🎧 Mic/speaker köprüsüsounddevice ile sistem ses cihazlarına bağla
  • 📦 Tip ipuçları her yerdepy.typed paketlenmiş

Hızlı başlangıç

Giden arama

import asyncio
from opensip import UserAgent, Account

async def main():
    ua = UserAgent(local_addr=("0.0.0.0", 5060))
    await ua.start()

    acc = Account(
        username="alice",
        domain="sip.example.com",
        password="s3cret",
        server=("sip.example.com", 5060),
    )
    await ua.register(acc)

    call = await ua.invite(acc, "sip:bob@sip.example.com")
    await call.wait_answered()
    await asyncio.sleep(10)
    await call.hangup()

    await ua.stop()

asyncio.run(main())

Gelen arama

import asyncio
from opensip import UserAgent, Account

async def main():
    ua = UserAgent(local_addr=("0.0.0.0", 5060))

    @ua.on_incoming_call
    async def handle(call):
        await call.answer()
        await call.wait_ended()

    await ua.start()
    acc = Account(username="alice", domain="sip.example.com",
                  password="s3cret", server=("sip.example.com", 5060))
    await ua.register(acc)
    await asyncio.Event().wait()  # sonsuza kadar bekle

asyncio.run(main())

Mikrofon ↔ uzak taraf köprüsü (audio extras ile)

from opensip.audio import AudioBridge

# ... yukarıdaki örnekteki gibi call'u kur ...

bridge = AudioBridge(sample_rate=8000)
bridge.start()
call.on_pcm(bridge.feed_speaker)         # uzak taraf → hoparlör

async def pump_mic():
    while call.is_active:
        pcm = await bridge.read_microphone()
        call.write_pcm(pcm)              # mikrofon → uzak taraf

asyncio.create_task(pump_mic())

Çalışan örnekler: examples/make_call.py, examples/receive_call.py.

API özeti

from opensip import UserAgent, Account, Call

UserAgent — top-level facade

Yöntem Açıklama
await ua.start() / stop() Transport'u aç / kapat
await ua.register(acc) REGISTER + otomatik yenileme
await ua.unregister(acc) Expires: 0 REGISTER
await ua.invite(acc, target)Call Giden çağrı kur
@ua.on_incoming_call Gelen INVITE handler decorator

Call — bir SIP dialog'u

Yöntem / property Açıklama
await call.wait_answered(timeout=None) 200 OK'i bekle
await call.wait_ended() BYE'ı bekle
await call.answer() UAS — gelen çağrıyı cevapla
await call.hangup() BYE gönder, RTP kapat
call.write_pcm(bytes) Uzak tarafa 16-bit PCM gönder
call.on_pcm(callback) Gelen PCM için handler
call.is_active Dialog "answered" durumunda mı
call.codec Anlaşılan codec (Codec nesnesi)

AudioBridge (opensip[audio] extras)

Yöntem Açıklama
bridge.start() / stop() Mikrofon + hoparlör stream'leri
await bridge.read_microphone() Bir frame PCM oku
bridge.feed_speaker(bytes) Hoparlöre PCM gönder

Performans

G.711 PCMU/PCMA hot path, numpy varsa vektörize LUT lookup'a düşer. Apple M-series üzerinde, 8 kHz × 20 ms × 16-bit frame için:

İşlem Saf-Python numpy Hızlanma
PCMU encode 13.1 µs/frame 1.0 µs/frame 13.6×
PCMU decode 25.8 µs/frame 1.0 µs/frame 25.3×
PCMA encode 12.4 µs/frame 1.0 µs/frame 12.7×
PCMA decode 25.6 µs/frame 1.0 µs/frame 24.4×

20 ms ptime bütçesinin %0.005'i — binlerce paralel çağrıda codec CPU yükü ihmal edilebilir. Çıktının bit-exact'liği 65,536 PCM değerinin tümü üzerinde doğrulanmıştır.

Yeniden üretmek için:

python tests/bench_codecs.py

Doğrulanmış provider'lar

Provider Sinyalleşme İki yönlü ses Notlar
netsantral.com Symmetric-RTP / SBC NAT handling sağlıyor
sip2sip.info ⚠️ test edilmedi Açık-kayıt test provider'ı, deneyebilirsiniz
Twilio SIP trunking (TLS) TLS-only; opensip henüz TLS desteklemiyor
Yerel Asterisk / FreeSWITCH 🟢 beklenen 🟢 beklenen LAN'da NAT olmadan çalışmalı

Mimari

opensip/
├── message.py     # SIP request/response parser + serializer (RFC 3261 §7-§20)
├── headers.py     # URI, NameAddr, Via — compact form, IPv6, quoted params
├── auth.py        # HTTP Digest (MD5/MD5-sess/SHA-256, qop=auth)
├── sdp.py         # SDP offer/answer (RFC 4566), audio m=line + codec seçimi
├── transport.py   # asyncio UDP transport
├── ua.py          # UserAgent — UAC + UAS facade, dialog state inline
├── rtp.py         # RTP packetization (RFC 3550) + 20 ms ptime sender loop
├── codecs.py      # G.711 µ-law / A-law — numpy hot path + pure-Python fallback
├── audio.py       # sounddevice wrapper (opsiyonel)
├── utils.py       # branch/tag/Call-ID üreteçleri, IP keşfi
└── exceptions.py  # Hata hiyerarşisi

Bilinen sınırlamalar

opensip v0.1 minimal-viable bir UA: gerçek bir provider ile çağrı yapar ama RFC 3261'in birkaç önemli parçası henüz yok. Telefon altyapısı kurmadan önce farkında olun.

  • Transaction katmanı yok (RFC 3261 §17). UDP retransmission timer'ları (Timer A–K) yok — paket düşerse istek timeout'a düşer. LAN / kayıpsız ağda fark edilmez; internet üzerinden kaybedilen ilk INVITE'ı tekrar göndermez.
  • Dialog state machine sınırlı. Re-INVITE (hold/resume), UPDATE, target refresh çalışmaz; route set INVITE/BYE/ACK'te kullanılmaz — uzun proxy zincirleri kırılır.
  • NAT handling client-side yok. SDP c= satırına LAN IP yazılır; iki yönlü RTP yalnızca provider symmetric-RTP / SBC NAT handling yapıyorsa çalışır (netsantral yapıyor, çoğu yapmaz). rport/received Contact'a yansıtılmaz, STUN/ICE yok.
  • Yalnızca UDP. TCP ve TLS yok; TLS-only provider'lar (bazı Twilio konfigürasyonları) için kullanılamaz.
  • RTCP yok. Jitter buffer yok — gelen RTP doğrudan callback'e gönderilir, out-of-order paket / sıralama boşluğu metrikleri yok.
  • DTMF yok. RFC 2833 payload type 101 alınır ama sessizce düşürülür.
  • Codec sınırlı. PCMU + PCMA + telephone-event (gönderme yok). Opus / G.722 / G.729 yok.
  • Authorization re-use yok. Her INVITE/BYE'da yeniden challenge — küçük gecikme katar.

Karşılaştırma

opensip aiosip baresip pjproject
Dil Pure Python Pure Python C C/C++
asyncio
Mic/speaker bridge
Transaction layer ❌ (roadmap)
NAT (ICE/STUN) ❌ (roadmap)
TLS / SRTP ❌ (roadmap)
Video
Wheel boyutu ~33 KB ~30 KB
Kullanım amacı Python-native scripting, prototip, embedded automation İlkel araştırma Production CLI/embedded Carrier-grade SDK

opensip "küçük, Python-native, hack'lemesi kolay" yönünde bir niş tutuyor. Carrier-grade telefon altyapısı için pjproject veya baresip + Python binding önerilir.

Yol haritası

  • Faz 1 — sağlamlaştırma: transaction katmanı (RFC 3261 §17), tam dialog state machine, rport/received NAT, TCP transport, RTCP SR/RR, jitter buffer, DTMF (RFC 2833 in/out)
  • Faz 2 — özellik: TLS + SRTP, ICE-lite (RFC 8445), Opus + G.722, MESSAGE/SUBSCRIBE/NOTIFY/REFER, re-INVITE/hold, video iskeleti
  • Faz 3 — test + perf: Docker'da Asterisk/Kamailio/FreeSWITCH entegrasyon testleri, parser fuzzing (hypothesis), zero-copy parsing

Detaylı önceliklendirme ve durum: issue tracker.

Geliştirme

git clone https://github.com/artan/opensip.git
cd opensip
python3.12 -m venv .venv
.venv/bin/pip install -e ".[dev,audio]"
.venv/bin/pytest -v          # 17 unit + 1 loopback testi
.venv/bin/ruff check src tests

Python 3.10+ gerekiyor. macOS Homebrew kullanıyorsan: brew install python@3.12.

G.711 mikrobenchmark:

.venv/bin/python tests/bench_codecs.py

Canlı arama testi: examples/.env.example'ı kopyalayıp credentials gir, ardından:

LOG_LEVEL=DEBUG .venv/bin/python examples/make_call.py

Katkı

PR'lar memnuniyetle. Açmadan önce:

  1. Public API değişikliği yapıyorsanız önce bir issue açın
  2. pytest ve ruff check src tests yeşil olmalı
  3. Yeni özelliklere unit test eklenmeli — özellikle parser/codec/auth modüllerinde
  4. Commit mesajları konvansiyonel format (feat:, fix:, docs:) tercih edilir ama zorunlu değil

Lisans

MIT © artan

Teşekkürler

  • numpy — G.711 vektörize hot path
  • sounddevice + PortAudio — mikrofon/hoparlör erişimi
  • hatchling — build sistemi
  • IETF RFC 3261, 3550, 4566, 7616 yazarları

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

opensip-0.1.1.tar.gz (36.4 kB view details)

Uploaded Source

Built Distribution

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

opensip-0.1.1-py3-none-any.whl (36.0 kB view details)

Uploaded Python 3

File details

Details for the file opensip-0.1.1.tar.gz.

File metadata

  • Download URL: opensip-0.1.1.tar.gz
  • Upload date:
  • Size: 36.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for opensip-0.1.1.tar.gz
Algorithm Hash digest
SHA256 ecf000f9a4348679713df121750bfef6ac8aacddbb97e53ce0f56ea8c6dcabbe
MD5 e839fdaf619b5d4fff79bed4c3ef232f
BLAKE2b-256 c3487afcc7478608fb8f4ccdaade5f9bd7710450e2ca2ff5a02a1e72cc928810

See more details on using hashes here.

File details

Details for the file opensip-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: opensip-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 36.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for opensip-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 043220d1f3fc1563202f895815861a3d5a540250ad747661c8a278dd74733768
MD5 3235eca1651c8a1d350ea69166744490
BLAKE2b-256 025702699ef136bd04ce9cb91521b9f70b7df57390cf00da67b10ea84c519aac

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