PySide6/PJSUA2-basiertes Desktop-Softphone mit: - SIP-Telefonie (Anrufe, DTMF, Halten, Transfer, Konferenz) - CardDAV-Kontaktsync mit Write-Back (Multi-Account) - Kontaktverwaltung mit Suche und Bearbeiten-Dialog - Anrufliste mit Namensauflösung - Favoriten-Panel (manuell + häufig angerufen) - BLF-Panel (SIP Presence Monitoring) - Responsives Layout (kompakt/erweitert) - Click-to-Call (tel:/sip: URI via D-Bus) - KDE-Integration (Tray, Benachrichtigungen) - PipeWire/PulseAudio Audio-Routing - AppImage Build-Support (PyInstaller + appimagetool) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
82 lines
2.5 KiB
Python
82 lines
2.5 KiB
Python
"""SIP-Account Klasse - Wrapper um pjsua2.Account für FreePBX-Registrierung."""
|
|
|
|
import pjsua2 as pj
|
|
|
|
from sip.call import MeinAnruf
|
|
|
|
|
|
class MeinAccount(pj.Account):
|
|
"""SIP-Account für FreePBX-Registrierung.
|
|
|
|
Verwaltet den Registrierungsstatus und eingehende Anrufe.
|
|
"""
|
|
|
|
def __init__(self, callback=None):
|
|
pj.Account.__init__(self)
|
|
self._callback = callback
|
|
self.aktueller_anruf = None
|
|
# Für Konferenz: Liste aller aktiven Anrufe
|
|
self.aktive_anrufe = []
|
|
|
|
def onRegState(self, prm):
|
|
"""Registrierungsstatus hat sich geändert."""
|
|
ai = self.getInfo()
|
|
if self._callback:
|
|
self._callback("registrierung", {
|
|
"aktiv": ai.regIsActive,
|
|
"code": prm.code,
|
|
"grund": prm.reason,
|
|
"uri": ai.uri,
|
|
})
|
|
|
|
def onIncomingCall(self, iprm):
|
|
"""Eingehender Anruf empfangen."""
|
|
anruf = MeinAnruf(self, iprm.callId, self._callback)
|
|
ci = anruf.getInfo()
|
|
|
|
# Als aktuellen Anruf setzen und in Liste aufnehmen
|
|
self.aktueller_anruf = anruf
|
|
self.aktive_anrufe.append(anruf)
|
|
|
|
if self._callback:
|
|
self._callback("eingehend", {
|
|
"remoteUri": ci.remoteUri,
|
|
"remoteContact": ci.remoteContact,
|
|
})
|
|
|
|
# 180 Ringing senden
|
|
prm = pj.CallOpParam()
|
|
prm.statusCode = pj.PJSIP_SC_RINGING
|
|
anruf.answer(prm)
|
|
|
|
def anruf_starten(self, ziel_uri):
|
|
"""Ausgehenden Anruf starten."""
|
|
anruf = MeinAnruf(self, callback=self._callback)
|
|
prm = pj.CallOpParam(True)
|
|
anruf.makeCall(ziel_uri, prm)
|
|
|
|
self.aktueller_anruf = anruf
|
|
self.aktive_anrufe.append(anruf)
|
|
return anruf
|
|
|
|
def anruf_annehmen(self):
|
|
"""Eingehenden Anruf annehmen (200 OK)."""
|
|
if self.aktueller_anruf:
|
|
prm = pj.CallOpParam()
|
|
prm.statusCode = pj.PJSIP_SC_OK
|
|
self.aktueller_anruf.answer(prm)
|
|
|
|
def anruf_beenden(self):
|
|
"""Aktuellen Anruf auflegen."""
|
|
if self.aktueller_anruf:
|
|
self.aktueller_anruf.auflegen()
|
|
|
|
def anruf_entfernen(self, anruf):
|
|
"""Beendeten Anruf aus der Liste entfernen."""
|
|
if anruf in self.aktive_anrufe:
|
|
self.aktive_anrufe.remove(anruf)
|
|
if self.aktueller_anruf is anruf:
|
|
# Nächsten aktiven Anruf als aktuell setzen
|
|
self.aktueller_anruf = (
|
|
self.aktive_anrufe[-1] if self.aktive_anrufe else None
|
|
)
|