Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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
  • 🧱 Jitter buffer — reorder + gap-fill (silence) + RFC 3550 §A.8 jitter ölçümü
  • ☎️ DTMF her iki yöndesend_dtmf() (RFC 4733) gönderim, on_dtmf callback ile alım
  • 📊 RTP istatistikleriRTPSession.stats ile paket/byte sayaçları + jitter
  • 📦 Tip ipuçları her yerdepy.typed paketlenmiş

Sürüm notları

0.2.0 (yeni)

  • Jitter bufferRTPSession'a varsayılan açık (jitter_ms=60). Sıra dışı paketleri yeniden sıralar, kayıp frame yerine sessizlik koyar, jitter_ms=0 ile devre dışı bırakılabilir.
  • JitterBuffer.recommended_target_ms() — RFC 3550 §A.8 EWMA ile ağ koşullarına göre hedef derinlik önerir.
  • DTMF alımı (RFC 4733)RTPSession.on_dtmf / Call.on_dtmf callback; sürdürme + 3 redundant end-packet otomatik dedup.
  • RTPSession.statspackets_sent/recv, bytes_sent/recv, dtmf_recv + iç içe jitter sub-stats.

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 (registrar'ın verdiği expiry'ye göre)
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
@ua.on_registration_state Kayıt durumu geçişleri için callback (sync veya async)
acc.registration_state Anlık kayıt durumu: unregistered / registered / degraded / lapsed
UserAgent(timers=TimerConfig(...)) Non-INVITE transaction timer'larını (T1/T2/Timer F) özelleştir

Transaction davranışı: REGISTER ve BYE, RFC 3261 §17.1.2 non-INVITE client transaction'ları üzerinden gönderilir — kayıp UDP paketleri Timer E ile yeniden iletilir. Final yanıt hiç gelmezse asyncio.TimeoutError değil, TransactionTimeout (bir TransactionError alt sınıfı, top-level export) yükselir. Kayıt registrar tarafından reddedilirse (expires=0) RegistrationError yükselir; kayıt süresi dolmuşsa yenileme, jitter'lı üstel geri çekilme (2s → 60s) ile sürer.

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 hâlâ erken alfa 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ı kısmi (RFC 3261 §17). Non-INVITE istekler (REGISTER/BYE) Timer E/F/K ile tam client transaction üzerinden gider; INVITE client/server transaction'ları henüz yok — internet üzerinden kaybedilen ilk INVITE yeniden gönderilmez.
  • 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. RTP istatistikleri ve jitter ölçümü var, ancak SR/RR paketleri ve RTCP tabanlı raporlama henüz yok.
  • Jitter buffer adaptif değil. Sabit hedef derinlikle reorder + gap-fill yapar; otomatik retune / drift management henüz yok.
  • DTMF kapsamı sınırlı. RFC 4733 giriş/çıkış temel akışı var, ancak SIP INFO veya daha gelişmiş interop senaryoları henüz yok.
  • 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 🟡 non-INVITE
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: INVITE transaction'ları (RFC 3261 §17 kalan kısmı), 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/artanergin44-collab/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ı

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages