Page MenuHomePhabricator

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/sipsimple/core/_core.invitation.pxi b/sipsimple/core/_core.invitation.pxi
index 52f07074..586614c9 100644
--- a/sipsimple/core/_core.invitation.pxi
+++ b/sipsimple/core/_core.invitation.pxi
@@ -1,1855 +1,1856 @@
import weakref
from errno import EADDRNOTAVAIL, ENETUNREACH
from operator import itemgetter
# classes
cdef class SDPPayloads:
def __init__(self):
self.proposed_local = None
self.proposed_remote = None
self.active_local = None
self.active_remote = None
cdef class StateCallbackTimer(Timer):
def __init__(self, state, sub_state, rdata, tdata, originator):
self.state = state
self.sub_state = sub_state
self.rdata = rdata
self.tdata = tdata
self.originator = originator
cdef class SDPCallbackTimer(Timer):
def __init__(self, int status, active_local, active_remote):
self.status = status
self.active_local = active_local
self.active_remote = active_remote
cdef class TransferStateCallbackTimer(Timer):
def __init__(self, state, code, reason):
self.state = state
self.code = code
self.reason = reason
cdef class TransferResponseCallbackTimer(Timer):
def __init__(self, method, rdata):
self.method = method
self.rdata = rdata
cdef class TransferRequestCallbackTimer(Timer):
def __init__(self, rdata):
self.rdata = rdata
class DialogID(tuple):
call_id = property(itemgetter(0))
local_tag = property(itemgetter(1))
remote_tag = property(itemgetter(2))
def __new__(cls, call_id, local_tag, remote_tag):
return tuple.__new__(cls, (call_id, local_tag, remote_tag))
def __repr__(self):
return 'DialogID(call_id=%r, local_tag=%r, remote_tag=%r)' % self
cdef class Invitation:
expire_warning_time = 30
def __cinit__(self, *args, **kwargs):
cdef int status
self.weakref = weakref.ref(self)
Py_INCREF(self.weakref)
status = pj_mutex_create_recursive(_get_ua()._pjsip_endpoint._pool, "invitation_lock", &self._lock)
if status != 0:
raise PJSIPError("failed to create lock", status)
pj_list_init(<pj_list *> &self._route_set)
self._invite_session = NULL
self._dialog = NULL
self._reinvite_transaction = NULL
self._transfer_usage = NULL
self._sdp_neg_status = -1
self._failed_response = 0
self._timer = None
self._transfer_timeout_timer = None
self._transfer_refresh_timer = None
self.from_header = None
self.to_header = None
self.request_uri = None
self.route_header = None
self.local_contact_header = None
self.remote_contact_header = None
self.credentials = None
self.sdp = SDPPayloads()
self.remote_user_agent = None
self.state = None
self.sub_state = None
self.transport = None
self.transfer_state = None
self.direction = None
self.call_id = None
self.peer_address = None
cdef int init_incoming(self, PJSIPUA ua, pjsip_rx_data *rdata, unsigned int inv_options) except -1:
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef pjmedia_sdp_session_ptr_const sdp
cdef pjsip_dialog *replaced_dialog = NULL
cdef pjsip_tpselector tp_sel
cdef pjsip_tx_data *tdata = NULL
cdef PJSTR contact_str
cdef char *error_message
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
# Validate replaces header
with nogil:
status = pjsip_replaces_verify_request(rdata, &replaced_dialog, 0, &tdata)
if status != 0:
if tdata != NULL:
pjsip_endpt_send_response2(ua._pjsip_endpoint._obj, rdata, tdata, NULL, NULL)
else:
pjsip_endpt_respond_stateless(ua._pjsip_endpoint._obj, rdata, 500, NULL, NULL, NULL)
if status != 0:
return 0
self.direction = "incoming"
self.transport = rdata.tp_info.transport.type_name.decode().lower()
self.request_uri = FrozenSIPURI_create(<pjsip_sip_uri *> pjsip_uri_get_uri(rdata.msg_info.msg.line.req.uri))
if _is_valid_ip(pj_AF_INET(), self.request_uri.host.encode()):
self.local_contact_header = FrozenContactHeader(self.request_uri)
else:
self.local_contact_header = FrozenContactHeader(FrozenSIPURI(host=_pj_str_to_str(rdata.tp_info.transport.local_name.host),
user=self.request_uri.user, port=rdata.tp_info.transport.local_name.port,
parameters=(frozendict(transport=self.transport) if self.transport != "udp" else frozendict())))
contact_str = PJSTR(str(self.local_contact_header.body).encode())
tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT
tp_sel.u.transport = rdata.tp_info.transport
with nogil:
status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata, &contact_str.pj_str, &self._dialog)
if status != 0:
error_message = "Could not create dialog for new INVITE session"
else:
pjsip_dlg_set_transport(self._dialog, &tp_sel)
status = pjsip_inv_create_uas(self._dialog, rdata, NULL, inv_options, &self._invite_session)
pjsip_dlg_dec_lock(self._dialog)
if status != 0:
error_message = "Could not create new INVITE session"
else:
status = pjsip_inv_initial_answer(self._invite_session, rdata, 100, NULL, NULL, &tdata)
if status != 0:
error_message = "Could not create initial (unused) response to INVITE"
else:
pjsip_tx_data_dec_ref(tdata)
if status != 0:
raise PJSIPError(error_message, status)
if self._invite_session.neg != NULL:
if pjmedia_sdp_neg_get_state(self._invite_session.neg) == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
pjmedia_sdp_neg_get_neg_remote(self._invite_session.neg, &sdp)
self.sdp.proposed_remote = FrozenSDPSession_create(sdp)
self._invite_session.sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE
self._invite_session.mod_data[ua._module.id] = <void *> self.weakref
self.call_id = _pj_str_to_str(self._dialog.call_id.id)
self.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
event_dict = dict(obj=self, prev_state=self.state, state="incoming", originator="remote")
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
print(event_dict)
self.state = "incoming"
self.remote_user_agent = event_dict['headers']['User-Agent'].body if 'User-Agent' in event_dict['headers'] else None
try:
self.remote_contact_header = event_dict['headers']['Contact'][0]
except LookupError:
pass
_add_event("SIPInvitationChangedState", event_dict)
self.from_header = FrozenFromHeader_create(rdata.msg_info.from_hdr)
self.to_header = FrozenToHeader_create(rdata.msg_info.to_hdr)
except:
if self._invite_session != NULL:
with nogil:
pjsip_inv_terminate(self._invite_session, 500, 0)
self._invite_session = NULL
elif self._dialog != NULL:
with nogil:
pjsip_dlg_terminate(self._dialog)
self._dialog = NULL
else:
with nogil:
status = pjsip_endpt_create_response(ua._pjsip_endpoint._obj, rdata, 500, NULL, &tdata)
if status != 0:
error_message = "Could not create response"
else:
status = pjsip_endpt_send_response2(ua._pjsip_endpoint._obj, rdata, tdata, NULL, NULL)
if status != 0:
pjsip_tx_data_dec_ref(tdata)
error_message = "Could not send response"
if status != 0:
raise PJSIPError(error_message, status)
raise
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int process_incoming_transfer(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
global _incoming_transfer_cb
global _event_hdr_name
cdef int status, status2
cdef dict rdata_dict = dict(obj=self)
cdef pjsip_tx_data *tdata
cdef pjsip_transaction *initial_tsx
cdef Timer timer
cdef char *error_message
if self._transfer_usage != NULL:
with nogil:
status = pjsip_endpt_create_response(ua._pjsip_endpoint._obj, rdata, 480, NULL, &tdata)
if status != 0:
error_message = "Could not create response"
else:
status = pjsip_endpt_send_response2(ua._pjsip_endpoint._obj, rdata, tdata, NULL, NULL)
if status != 0:
pjsip_tx_data_dec_ref(tdata)
error_message = "Could not send response"
if status != 0:
raise PJSIPError(error_message, status)
return 0
_pjsip_msg_to_dict(rdata.msg_info.msg, rdata_dict)
try:
refer_to_hdr = rdata_dict["headers"]["Refer-To"]
SIPURI.parse(refer_to_hdr.uri)
except (KeyError, SIPCoreError):
with nogil:
status = pjsip_endpt_create_response(ua._pjsip_endpoint._obj, rdata, 400, NULL, &tdata)
if status != 0:
error_message = "Could not create response"
else:
status = pjsip_endpt_send_response2(ua._pjsip_endpoint._obj, rdata, tdata, NULL, NULL)
if status != 0:
pjsip_tx_data_dec_ref(tdata)
error_message = "Could not send response"
if status != 0:
raise PJSIPError(error_message, status)
return 0
try:
self._set_transfer_state("INCOMING")
_add_event("SIPInvitationTransferNewIncoming", rdata_dict)
# PJSIP event framework needs an Event header, even if it's not needed for REFER, so we insert a fake one
event_header = <pjsip_event_hdr *> pjsip_msg_find_hdr_by_name(rdata.msg_info.msg, &_event_hdr_name.pj_str, NULL)
if event_header == NULL:
event_header = pjsip_event_hdr_create(rdata.tp_info.pool)
event_header.event_type = _refer_event.pj_str
pjsip_msg_add_hdr(rdata.msg_info.msg, <pjsip_hdr *> event_header)
initial_tsx = pjsip_rdata_get_tsx(rdata)
with nogil:
status = pjsip_evsub_create_uas(self._dialog, &_incoming_transfer_cb, rdata, 0, &self._transfer_usage)
if status != 0:
pjsip_tsx_terminate(initial_tsx, 500)
error_message = "Could not create incoming REFER session"
else:
self._transfer_usage_role = PJSIP_ROLE_UAS
pjsip_evsub_set_mod_data(self._transfer_usage, ua._event_module.id, <void *> self.weakref)
status = pjsip_dlg_create_response(self._dialog, rdata, 202, NULL, &tdata)
if status != 0:
pjsip_tsx_terminate(initial_tsx, 500)
error_message = "Could not create response for incoming REFER"
else:
pjsip_evsub_update_expires(self._transfer_usage, 90)
status = pjsip_dlg_send_response(self._dialog, initial_tsx, tdata)
if status != 0:
status2 = pjsip_dlg_modify_response(self._dialog, tdata, 500, NULL)
if status2 != 0:
error_message = "Could not modify response"
status = status2
else:
pjsip_tx_data_dec_ref(tdata) # pjsip_dlg_modify_response() increases ref count unnecessarily
error_message = "Could not send response"
if status != 0:
raise PJSIPError(error_message, status)
except PJSIPError, e:
code = 0
reason = e.args[0]
if self._transfer_usage != NULL:
with nogil:
pjsip_evsub_terminate(self._transfer_usage, 0)
# Manually trigger the state callback since we handle the timeout ourselves
state_timer = TransferStateCallbackTimer("TERMINATED", code, reason)
state_timer.schedule(0, <timer_callback>self._transfer_cb_state, self)
raise
else:
self._set_transfer_state("ACTIVE")
_add_event("SIPInvitationTransferDidStart", dict(obj=self))
timer = Timer()
timer.schedule(0, <timer_callback>self._start_incoming_transfer, self)
return 0
cdef int process_incoming_options(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
cdef pjsip_tx_data *tdata
cdef pjsip_transaction *initial_tsx
cdef int status
cdef char *error_message
initial_tsx = pjsip_rdata_get_tsx(rdata)
with nogil:
status = pjsip_dlg_create_response(self._dialog, rdata, 200, NULL, &tdata)
if status != 0:
pjsip_tsx_terminate(initial_tsx, 500)
error_message = "Could not create response for incoming OPTIONS"
else:
status = pjsip_dlg_send_response(self._dialog, initial_tsx, tdata)
if status != 0:
error_message = "Could not send response"
if status != 0:
raise PJSIPError(error_message, status)
def send_invite(self, SIPURI request_uri not None, FromHeader from_header not None, ToHeader to_header not None, RouteHeader route_header not None, ContactHeader contact_header not None,
SDPSession sdp not None, Credentials credentials=None, list extra_headers not None=list(), timeout=None):
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef pjmedia_sdp_session *local_sdp
cdef pjsip_cred_info *cred_info
cdef pjsip_replaces_hdr *pj_replaces_hdr
cdef pjsip_route_hdr *route_set
cdef pjsip_tx_data *tdata
cdef PJSIPUA ua
cdef PJSTR contact_str
cdef PJSTR from_header_str
cdef PJSTR to_header_str
cdef PJSTR request_uri_str
ua = _get_ua()
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
route_set = <pjsip_route_hdr *> &self._route_set
if self.state is not None:
raise SIPCoreInvalidStateError('Can only transition to the "outgoing" state from the "None" state, currently in the "%s" state' % self.state)
if timeout is not None and timeout <= 0:
raise ValueError("Timeout value must be positive")
self.transport = route_header.uri.transport
self.direction = "outgoing"
self.credentials = FrozenCredentials.new(credentials) if credentials is not None else None
self.request_uri = FrozenSIPURI.new(request_uri)
self.route_header = FrozenRouteHeader.new(route_header)
self.route_header.uri.parameters.dict[b"lr"] = None # always send lr parameter in Route header
self.route_header.uri.parameters.dict[b"hide"] = None # always hide Route header
self.local_contact_header = FrozenContactHeader.new(contact_header)
self.sdp.proposed_local = FrozenSDPSession.new(sdp) if sdp is not None else None
from_header_parameters = from_header.parameters.copy()
from_header_parameters.pop("tag", None)
from_header.parameters = {}
from_header_str = PJSTR(from_header.body)
to_header_parameters = to_header.parameters.copy()
to_header_parameters.pop("tag", None)
to_header.parameters = {}
to_header_str = PJSTR(to_header.body)
contact_str = PJSTR(str(self.local_contact_header.body))
request_uri_str = PJSTR(str(request_uri))
with nogil:
status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from_header_str.pj_str, &contact_str.pj_str,
&to_header_str.pj_str, &request_uri_str.pj_str, &self._dialog)
if status != 0:
raise PJSIPError("Could not create dialog for outgoing INVITE session", status)
with nogil:
pjsip_dlg_inc_lock(self._dialog)
if contact_header.expires is not None:
self._dialog.local.contact.expires = contact_header.expires
if contact_header.q is not None:
self._dialog.local.contact.q1000 = int(contact_header.q*1000)
contact_parameters = contact_header.parameters.copy()
contact_parameters.pop("q", None)
contact_parameters.pop("expires", None)
_dict_to_pjsip_param(contact_parameters, &self._dialog.local.contact.other_param, self._dialog.pool)
_dict_to_pjsip_param(from_header_parameters, &self._dialog.local.info.other_param, self._dialog.pool)
_dict_to_pjsip_param(to_header_parameters, &self._dialog.remote.info.other_param, self._dialog.pool)
self.from_header = FrozenFromHeader_create(self._dialog.local.info)
self.to_header = FrozenToHeader.new(to_header)
self.call_id = _pj_str_to_str(self._dialog.call_id.id)
local_sdp = self.sdp.proposed_local.get_sdp_session() if sdp is not None else NULL
with nogil:
status = pjsip_inv_create_uac(self._dialog, local_sdp, 0, &self._invite_session)
if status != 0:
raise PJSIPError("Could not create outgoing INVITE session", status)
self._invite_session.sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE
self._invite_session.mod_data[ua._module.id] = <void *> self.weakref
if self.credentials is not None:
cred_info = self.credentials.get_cred_info()
with nogil:
status = pjsip_auth_clt_set_credentials(&self._dialog.auth_sess, 1, cred_info)
if status != 0:
raise PJSIPError("Could not set credentials for INVITE session", status)
_BaseRouteHeader_to_pjsip_route_hdr(self.route_header, &self._route_header, self._dialog.pool)
pj_list_insert_after(<pj_list *> &self._route_set, <pj_list *> &self._route_header)
with nogil:
status = pjsip_dlg_set_route_set(self._dialog, route_set)
if status != 0:
raise PJSIPError("Could not set route for INVITE session", status)
with nogil:
status = pjsip_inv_invite(self._invite_session, &tdata)
if status != 0:
raise PJSIPError("Could not create INVITE message", status)
replaces_headers = [header for header in extra_headers if isinstance(header, BaseReplacesHeader)]
if len(replaces_headers) > 1:
raise SIPCoreError("Only one Replaces header is allowed")
try:
replaces_header = replaces_headers[0]
except IndexError:
pass
else:
extra_headers.remove(replaces_header)
pj_replaces_hdr = pjsip_replaces_hdr_create(self._dialog.pool)
_str_to_pj_str(replaces_header.call_id, &pj_replaces_hdr.call_id)
_str_to_pj_str(replaces_header.to_tag, &pj_replaces_hdr.to_tag)
_str_to_pj_str(replaces_header.from_tag, &pj_replaces_hdr.from_tag)
_dict_to_pjsip_param(replaces_header.parameters, &pj_replaces_hdr.other_param, self._dialog.pool)
pjsip_msg_add_hdr(tdata.msg, <pjsip_hdr *>pj_replaces_hdr)
_add_headers_to_tdata(tdata, extra_headers)
with nogil:
status = pjsip_inv_send_msg(self._invite_session, tdata)
if status != 0:
raise PJSIPError("Could not send initial INVITE", status)
if timeout is not None:
self._timer = Timer()
self._timer.schedule(timeout, <timer_callback>self._cb_timer_disconnect, self)
with nogil:
pjsip_dlg_dec_lock(self._dialog)
except Exception, e:
if isinstance(e, PJSIPError) and e.errno == EADDRNOTAVAIL:
self._invite_session = NULL
pjsip_dlg_dec_lock(self._dialog)
self._dialog = NULL
raise
if self._invite_session != NULL:
pjsip_inv_terminate(self._invite_session, 500, 0)
self._invite_session = NULL
elif self._dialog != NULL:
pjsip_dlg_dec_lock(self._dialog)
self._dialog = NULL
raise
finally:
with nogil:
pj_mutex_unlock(lock)
def send_response(self, int code, str reason=None, BaseContactHeader contact_header=None, BaseSDPSession sdp=None, list extra_headers not None=list()):
cdef int status
cdef int clean_tdata = 0
cdef pj_mutex_t *lock = self._lock
cdef pj_str_t reason_str
cdef pjmedia_sdp_session_ptr_const lsdp = NULL
cdef pjmedia_sdp_session *local_sdp
cdef pjsip_inv_session *invite_session
cdef pjsip_msg_body *body
cdef pjsip_tx_data *tdata
cdef PJSIPUA ua
ua = _get_ua()
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
invite_session = self._invite_session
if reason is not None:
_str_to_pj_str(reason, &reason_str)
if self.state not in ("incoming", "early", "connected"):
raise SIPCoreInvalidStateError('Can only send response from the "incoming", "early" and "connected" states current in the "%s" state.' % self.state)
if self.state == "early" and self.direction != "incoming":
raise SIPCoreInvalidStateError('Cannot send response in the "early" state for an outgoing INVITE')
if self.state == "connected" and self.sub_state not in ("received_proposal", "received_proposal_request"):
raise SIPCoreInvalidStateError('Cannot send response in the "connected" state if a proposal has not been received')
if contact_header is not None:
self._update_contact_header(contact_header)
if 200 <= code < 300 and sdp is None:
raise SIPCoreError("Local SDP needs to be set for a positive response")
if code >= 300 and sdp is not None:
raise SIPCoreError("Local SDP cannot be specified for a negative response")
self.sdp.proposed_local = FrozenSDPSession.new(sdp) if sdp is not None else None
local_sdp = self.sdp.proposed_local.get_sdp_session() if sdp is not None else NULL
if sdp is not None and self.sdp.proposed_remote is None:
# There was no remote proposal, this is a reply with an offer
with nogil:
status = pjmedia_sdp_neg_modify_local_offer(self._dialog.pool, invite_session.neg, <pjmedia_sdp_session_ptr_const>local_sdp)
if status != 0:
raise PJSIPError("Could not modify local SDP offer", status)
# Retrieve the "fixed" offer from negotiator
pjmedia_sdp_neg_get_neg_local(invite_session.neg, &lsdp)
local_sdp = <pjmedia_sdp_session *>lsdp
with nogil:
status = pjsip_inv_answer(invite_session, code, &reason_str if reason is not None else NULL, local_sdp, &tdata)
if status != 0:
raise PJSIPError("Could not create %d reply to INVITE" % code, status)
_add_headers_to_tdata(tdata, extra_headers)
with nogil:
status = pjsip_inv_send_msg(invite_session, tdata)
if status != 0:
exc = PJSIPError("Could not send %d response" % code, status)
if sdp is not None and self.sdp.proposed_remote is not None and exc.errno in (EADDRNOTAVAIL, ENETUNREACH):
self._failed_response = 1
raise exc
self._failed_response = 0
finally:
with nogil:
pj_mutex_unlock(lock)
def send_reinvite(self, BaseContactHeader contact_header=None, BaseSDPSession sdp=None, list extra_headers not None=list()):
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef pjmedia_sdp_session *local_sdp
cdef pjsip_inv_session *invite_session
cdef pjsip_tx_data *tdata
cdef PJSIPUA ua
ua = _get_ua()
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
invite_session = self._invite_session
if self.state != "connected":
raise SIPCoreError('Can only send re-INVITE in "connected" state, not "%s" state' % self.state)
if self.sub_state != "normal":
raise SIPCoreError('Can only send re-INVITE if no another re-INVITE transaction is active')
if contact_header is not None:
self._update_contact_header(contact_header)
self.sdp.proposed_local = FrozenSDPSession.new(sdp) if sdp is not None else self.sdp.active_local
local_sdp = self.sdp.proposed_local.get_sdp_session()
with nogil:
status = pjsip_inv_reinvite(invite_session, NULL, local_sdp, &tdata)
if status != 0:
raise PJSIPError("Could not create re-INVITE message", status)
_add_headers_to_tdata(tdata, extra_headers)
with nogil:
status = pjsip_inv_send_msg(invite_session, tdata)
if status != 0:
raise PJSIPError("Could not send re-INVITE", status)
self._failed_response = 0
# TODO: use a callback tiner here instead?
self._reinvite_transaction = self._invite_session.invite_tsx
self.sub_state = "sent_proposal"
event_dict = dict(obj=self, prev_state="connected", state="connected", prev_sub_state="normal", sub_state="sent_proposal", originator="local")
_pjsip_msg_to_dict(tdata.msg, event_dict)
_add_event("SIPInvitationChangedState", event_dict)
finally:
with nogil:
pj_mutex_unlock(lock)
def cancel_reinvite(self):
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef pjsip_inv_session *invite_session
cdef pjsip_tx_data *tdata
cdef PJSIPUA ua
ua = _get_ua()
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
invite_session = self._invite_session
if not self.sub_state == "sent_proposal":
raise SIPCoreError("re-INVITE can only be cancelled if INVITE session is in 'sent_proposal' sub state")
if self._invite_session == NULL:
raise SIPCoreError("INVITE session is not active")
if self._reinvite_transaction == NULL:
raise SIPCoreError("there is no active re-INVITE transaction")
with nogil:
status = pjsip_inv_cancel_reinvite(invite_session, &tdata)
if status != 0:
raise PJSIPError("Could not create message to CANCEL re-INVITE transaction", status)
if tdata != NULL:
with nogil:
status = pjsip_inv_send_msg(invite_session, tdata)
if status != 0:
raise PJSIPError("Could not send %s" % _pj_str_to_str(tdata.msg.line.req.method.name), status)
finally:
with nogil:
pj_mutex_unlock(lock)
def transfer(self, SIPURI target_uri, object replaced_dialog_id=None, list extra_headers not None=list()):
global _refer_event
global _refer_method
cdef int status
cdef PJSIPUA ua
cdef pj_mutex_t *lock = self._lock
cdef pjsip_method refer_method
cdef pjsip_tx_data *tdata
cdef dict tdata_dict = dict(obj=self)
ua = _get_ua()
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
if self.state != "connected":
raise SIPCoreError('Can only start transfer in "connected" state, not "%s" state' % self.state)
if self._transfer_usage != NULL:
raise SIPCoreError('Another transfer is in progress')
with nogil:
status = pjsip_evsub_create_uac(self._dialog, &_transfer_cb, &_refer_event.pj_str, PJSIP_EVSUB_NO_EVENT_ID, &self._transfer_usage)
if status != 0:
raise PJSIPError("Could not create REFER", status)
self._transfer_usage_role = PJSIP_ROLE_UAC
pjsip_evsub_set_mod_data(self._transfer_usage, ua._event_module.id, <void *> self.weakref)
pjsip_method_init_np(&refer_method, &_refer_method.pj_str)
with nogil:
status = pjsip_evsub_initiate(self._transfer_usage, &refer_method, -1, &tdata)
if status != 0:
raise PJSIPError("Could not create REFER message", status)
if replaced_dialog_id is not None and None not in replaced_dialog_id:
target_uri.headers["Replaces"] = "%s;from-tag=%s;to-tag=%s" % replaced_dialog_id
refer_to_header = ReferToHeader(str(target_uri))
_add_headers_to_tdata(tdata, [refer_to_header, Header('Referred-By', str(self.local_identity.uri))])
_add_headers_to_tdata(tdata, extra_headers)
# We can't remove the Event header or PJSIP will fail to match responses to this request
_remove_headers_from_tdata(tdata, ["Expires"])
with nogil:
status = pjsip_evsub_send_request(self._transfer_usage, tdata)
if status != 0:
raise PJSIPError("Could not send REFER message", status)
_pjsip_msg_to_dict(tdata.msg, tdata_dict)
_add_event("SIPInvitationTransferNewOutgoing", tdata_dict)
self._transfer_timeout_timer = Timer()
self._transfer_timeout_timer.schedule(90, <timer_callback>self._transfer_cb_timeout_timer, self)
finally:
with nogil:
pj_mutex_unlock(lock)
def notify_transfer_progress(self, int code, str reason=None):
cdef int status
cdef PJSIPUA ua
cdef pj_mutex_t *lock = self._lock
ua = _get_ua()
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
if self._transfer_usage == NULL:
raise SIPCoreError("No transfer is in progress")
if self._transfer_usage_role != PJSIP_ROLE_UAS:
raise SIPCoreError("Transfer progress can only be notified by the transfer UAS")
self._set_sipfrag_payload(code, reason)
if 200 <= code < 700:
self._terminate_transfer_uas()
else:
self._send_notify()
finally:
with nogil:
pj_mutex_unlock(lock)
def end(self, list extra_headers not None=list(), timeout=None):
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef pjsip_inv_session *invite_session
cdef pjsip_tx_data *tdata
cdef PJSIPUA ua
ua = _get_ua()
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
invite_session = self._invite_session
if self.state == "disconnected":
return
if self.state == "disconnecting":
raise SIPCoreError('INVITE session is already in the "disconnecting" state')
if self._invite_session == NULL:
raise SIPCoreError("INVITE session is not active")
if self.state not in ("outgoing", "early", "connecting", "connected"):
raise SIPCoreError('Can only end the INVITE dialog from the "outgoing", "early", "connecting" and "connected" states' +
'current in the "%s" state.' % self.state)
if self.state == "early" and self.direction != "outgoing":
raise SIPCoreError('Cannot end incoming INVITE dialog while in the "early" state')
if timeout is not None and timeout <= 0:
raise ValueError("Timeout value cannot be negative")
# End ongoing transfer
self._terminate_transfer()
with nogil:
status = pjsip_inv_end_session(invite_session, 0, NULL, &tdata)
if status != 0:
raise PJSIPError("Could not create message to end INVITE session", status)
if tdata != NULL:
_add_headers_to_tdata(tdata, extra_headers)
with nogil:
status = pjsip_inv_send_msg(invite_session, tdata)
if status != 0:
raise PJSIPError("Could not send %s" % _pj_str_to_str(tdata.msg.line.req.method.name), status)
if self._timer is not None:
self._timer.cancel()
self._timer = None
if timeout is not None and timeout > 0:
self._timer = Timer()
self._timer.schedule(timeout, <timer_callback>self._cb_timer_disconnect, self)
event_dict = dict(obj=self, prev_state=self.state, state="disconnecting", originator="local")
if self.state == "connected":
event_dict["prev_sub_state"] = self.sub_state
self.state = "disconnecting"
self.sub_state = None
if tdata != NULL:
_pjsip_msg_to_dict(tdata.msg, event_dict)
_add_event("SIPInvitationChangedState", event_dict)
finally:
with nogil:
pj_mutex_unlock(lock)
property local_identity:
def __get__(self):
if self.direction == 'outgoing':
return self.from_header
elif self.direction == 'incoming':
return self.to_header
else:
return None
property remote_identity:
def __get__(self):
if self.direction == 'incoming':
return self.from_header
elif self.direction == 'outgoing':
return self.to_header
else:
return None
property dialog_id:
def __get__(self):
local_tag = remote_tag = None
if self.local_identity is not None:
local_tag = self.local_identity.tag
if self.remote_identity is not None:
remote_tag = self.remote_identity.tag
return DialogID(self.call_id, local_tag, remote_tag)
cdef PJSIPUA _check_ua(self):
try:
return _get_ua()
except:
self.state = "disconnected"
self.sub_state = None
self._dialog = NULL
self._invite_session = NULL
self._reinvite_transaction = NULL
cdef int _do_dealloc(self) except -1:
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef pjsip_inv_session *invite_session
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
invite_session = self._invite_session
if self._invite_session != NULL:
self._invite_session.mod_data[ua._module.id] = NULL
if self.state != "disconnecting":
with nogil:
pjsip_inv_terminate(invite_session, 481, 0)
self._dialog = NULL
self._invite_session = NULL
self._reinvite_transaction = NULL
if self._timer is not None:
self._timer.cancel()
self._timer = None
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
def __dealloc__(self):
cdef Timer timer
self._do_dealloc()
if self._lock != NULL:
pj_mutex_destroy(self._lock)
timer = Timer()
try:
timer.schedule(60, deallocate_weakref, self.weakref)
except SIPCoreError:
pass
cdef int _update_contact_header(self, BaseContactHeader contact_header) except -1:
# The PJSIP functions called here don't do much, so there is no need to call them
# without the gil.
cdef pj_str_t contact_str_pj
cdef pjsip_uri *contact
contact_str = str(contact_header.uri)
if contact_header.display_name:
- contact_str = "%s <%s>" % (contact_header.display_name.encode('utf-8'), contact_str)
- pj_strdup2_with_null(self._dialog.pool, &contact_str_pj, contact_str)
+ contact_str = "%s <%s>" % (contact_header.display_name, contact_str)
+ print('Built contact_str %s' % contact_str)
+ pj_strdup2_with_null(self._dialog.pool, &contact_str_pj, contact_str.encode())
contact = pjsip_parse_uri(self._dialog.pool, contact_str_pj.ptr, contact_str_pj.slen, PJSIP_PARSE_URI_AS_NAMEADDR)
if contact == NULL:
raise SIPCoreError("Not a valid Contact header: %s" % contact_str)
self._dialog.local.contact = pjsip_contact_hdr_create(self._dialog.pool)
self._dialog.local.contact.uri = contact
if contact_header.expires is not None:
self._dialog.local.contact.expires = contact_header.expires
if contact_header.q is not None:
self._dialog.local.contact.q1000 = int(contact_header.q*1000)
parameters = contact_header.parameters.copy()
parameters.pop("q", None)
parameters.pop("expires", None)
_dict_to_pjsip_param(parameters, &self._dialog.local.contact.other_param, self._dialog.pool)
self.local_contact_header = FrozenContactHeader.new(contact_header)
return 0
cdef int _fail(self, PJSIPUA ua) except -1:
cdef Timer timer
ua._handle_exception(0)
if self._transfer_usage != NULL:
with nogil:
pjsip_evsub_terminate(self._transfer_usage, 0)
pjsip_evsub_set_mod_data(self._transfer_usage, ua._event_module.id, NULL)
if self._transfer_timeout_timer is not None:
self._transfer_timeout_timer.cancel()
self._transfer_timeout_timer = None
if self._transfer_refresh_timer is not None:
self._transfer_refresh_timer.cancel()
self._transfer_refresh_timer = None
self._transfer_usage = NULL
_add_event("SIPInvitationTransferDidFail", dict(obj=self, code=0, reason="internal error"))
self._invite_session.mod_data[ua._module.id] = NULL
if self.state != "disconnected":
event_dict = dict(obj=self, prev_state=self.state, state="disconnected", originator="local", code=0, reason="internal error", disconnect_reason="internal error")
if self.state == "connected":
event_dict["prev_sub_state"] = self.sub_state
self.state = "disconnected"
self.sub_state = None
_add_event("SIPInvitationChangedState", event_dict)
# calling do_dealloc from within a callback makes PJSIP crash
# the handler will be executed after pjsip_endpt_handle_events returns
timer = Timer()
timer.schedule(0, <timer_callback>self._cb_postpoll_fail, self)
return 0
cdef int _cb_state(self, StateCallbackTimer timer) except -1:
cdef int status
cdef bint pjsip_error = False
cdef pj_mutex_t *lock = self._lock
cdef pjmedia_sdp_session_ptr_const sdp
cdef pjsip_inv_session *invite_session
cdef object state
cdef object sub_state
cdef object rdata
cdef object tdata
cdef object originator
cdef PJSIPUA ua
ua = self._check_ua()
if ua is None:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
invite_session = self._invite_session
state = timer.state
sub_state = timer.sub_state
rdata = timer.rdata
tdata = timer.tdata
originator = timer.originator
if state != "early" and state == self.state and sub_state == self.sub_state:
return 0
if state == "connected":
if self.state == "connecting" and self._sdp_neg_status != 0:
self.end()
return 0
if state == "disconnected" and self.state != "disconnecting":
# the invite session may have been destroyed if it failed
if not self._invite_session:
return 0
# we either sent a cancel or a negative reply to an incoming INVITE
if self._invite_session.cancelling or (self.state in ("incoming", "early") and self.direction == "incoming" and rdata is None):
# we caused the disconnect so send the transition to the disconnecting state
pjsip_error = True
event_dict = dict(obj=self, prev_state=self.state, state="disconnecting", originator="local")
self.state = "disconnecting"
_add_event("SIPInvitationChangedState", event_dict)
if self.direction == "outgoing" and state in ('connecting', 'connected') and self.state in ('outgoing', 'early') and rdata is not None:
self.to_header = rdata['headers']['To']
if self.direction == "incoming" and state in ('connecting', 'connected') and self.state in ('incoming', 'early') and tdata is not None:
self.to_header = tdata['headers']['To']
event_dict = dict(obj=self, prev_state=self.state, state=state)
if self.state == "connected":
event_dict["prev_sub_state"] = self.sub_state
if state == "connected":
event_dict["sub_state"] = sub_state
event_dict["originator"] = originator
if rdata is not None:
event_dict.update(rdata)
if tdata is not None:
event_dict.update(tdata)
if rdata is None and tdata is None:
event_dict['headers'] = dict()
event_dict['body'] = None
if self.remote_user_agent is None and state in ('connecting', 'connected') and rdata is not None:
if 'User-Agent' in event_dict['headers']:
self.remote_user_agent = event_dict['headers']['User-Agent'].body
elif 'Server' in event_dict['headers']:
self.remote_user_agent = event_dict['headers']['Server'].body
if state not in ('disconnecting', 'disconnected') and rdata is not None:
try:
self.remote_contact_header = event_dict['headers']['Contact'][0]
except LookupError:
pass
if state == "connected":
if sub_state == "received_proposal":
self._reinvite_transaction = self._invite_session.invite_tsx
if pjmedia_sdp_neg_get_state(self._invite_session.neg) == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
pjmedia_sdp_neg_get_neg_remote(self._invite_session.neg, &sdp)
self.sdp.proposed_remote = FrozenSDPSession_create(sdp)
elif sub_state == "sent_proposal":
if pjmedia_sdp_neg_get_state(self._invite_session.neg) == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
pjmedia_sdp_neg_get_neg_local(self._invite_session.neg, &sdp)
self.sdp.proposed_local = FrozenSDPSession_create(sdp)
elif sub_state == "received_proposal_request":
self._reinvite_transaction = self._invite_session.invite_tsx
if pjmedia_sdp_neg_get_state(self._invite_session.neg) == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
pjmedia_sdp_neg_get_neg_local(self._invite_session.neg, &sdp)
self.sdp.proposed_local = FrozenSDPSession_create(sdp)
elif self.sub_state in ("received_proposal", "sent_proposal", "received_proposal_request"):
if (rdata, tdata) == (None, None):
event_dict['code'] = 408
event_dict['reason'] = 'Request Timeout'
if pjmedia_sdp_neg_get_state(self._invite_session.neg) in (PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER):
pjmedia_sdp_neg_cancel_offer(self._invite_session.neg)
self._reinvite_transaction = NULL
if state == "disconnected":
event_dict["disconnect_reason"] = "user request" if not pjsip_error else "internal error"
event_dict["code"] = self._invite_session.cause
if self._invite_session.cause > 0:
event_dict["reason"] = _pj_str_to_str(self._invite_session.cause_text)
else:
event_dict["reason"] = ""
if not self._invite_session.cancelling and rdata is None and self._invite_session.cause > 0:
# pjsip internally generates 408 and 503
if self._invite_session.cause == 408:
if self.direction == "incoming" and self.state == "connecting":
event_dict["disconnect_reason"] = "missing ACK"
else:
event_dict["disconnect_reason"] = "timeout"
else:
event_dict["disconnect_reason"] = _pj_str_to_str(self._invite_session.cause_text)
elif self._invite_session.cancelling and rdata is None and self._invite_session.cause == 408 and self.state == "disconnecting":
# silly pjsip sets cancelling field when we call pjsip_inv_end_session in end even if we send a BYE
event_dict["disconnect_reason"] = "timeout"
elif rdata is not None and 'Reason' in event_dict['headers']:
try:
reason = event_dict['headers']['Reason'].text
if reason:
event_dict["disconnect_reason"] = reason
except (ValueError, IndexError):
pass
if self._transfer_usage != NULL:
with nogil:
pjsip_evsub_terminate(self._transfer_usage, 0)
pjsip_evsub_set_mod_data(self._transfer_usage, ua._event_module.id, NULL)
if self._transfer_timeout_timer is not None:
self._transfer_timeout_timer.cancel()
self._transfer_timeout_timer = None
if self._transfer_refresh_timer is not None:
self._transfer_refresh_timer.cancel()
self._transfer_refresh_timer = None
self._transfer_usage = NULL
_add_event("SIPInvitationTransferDidFail", dict(obj=self, code=0, reason="invite dialog ended"))
self._invite_session.mod_data[ua._module.id] = NULL
self._invite_session = NULL
self._dialog = NULL
if self._timer is not None:
self._timer.cancel()
self._timer = None
elif state in ("early", "connecting") and self._timer is not None:
self._timer.cancel()
self._timer = None
self.state = state
self.sub_state = sub_state
_add_event("SIPInvitationChangedState", event_dict)
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int _cb_sdp_done(self, SDPCallbackTimer timer) except -1:
cdef int status
cdef pj_mutex_t *lock = self._lock
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
if self._failed_response == 1:
return 0
self._sdp_neg_status = timer.status
self.sdp.proposed_local = None
self.sdp.proposed_remote = None
if timer.status == 0:
self.sdp.active_local = timer.active_local
self.sdp.active_remote = timer.active_remote
if self.state in ["disconnecting", "disconnected"]:
return 0
event_dict = dict(obj=self, succeeded=timer.status == 0)
if timer.status == 0:
event_dict["local_sdp"] = self.sdp.active_local
event_dict["remote_sdp"] = self.sdp.active_remote
else:
event_dict["error"] = _pj_status_to_str(timer.status)
_add_event("SIPInvitationGotSDPUpdate", event_dict)
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int _cb_timer_disconnect(self, timer) except -1:
cdef pjsip_inv_session *invite_session = self._invite_session
with nogil:
pjsip_inv_terminate(invite_session, 408, 1)
cdef int _cb_postpoll_fail(self, timer) except -1:
self._do_dealloc()
cdef int _start_incoming_transfer(self, timer) except -1:
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef PJSIPUA ua
ua = self._check_ua()
if ua is None:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
self._set_sipfrag_payload(100, "Trying")
self._send_notify()
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int _terminate_transfer(self) except -1:
if self._transfer_usage == NULL:
return 0
if self._transfer_usage_role == PJSIP_ROLE_UAC:
self._terminate_transfer_uac()
else:
self._terminate_transfer_uas()
cdef int _terminate_transfer_uac(self) except -1:
cdef pjsip_tx_data *tdata
cdef int status
cdef TransferStateCallbackTimer state_timer
try:
with nogil:
status = pjsip_evsub_initiate(self._transfer_usage, NULL, 0, &tdata)
if status != 0:
raise PJSIPError("Could not create SUBSCRIBE message", status)
with nogil:
status = pjsip_evsub_send_request(self._transfer_usage, tdata)
if status != 0:
raise PJSIPError("Could not send SUBSCRIBE message", status)
if self._transfer_timeout_timer is not None:
self._transfer_timeout_timer.cancel()
self._transfer_timeout_timer = None
if self._transfer_refresh_timer is not None:
self._transfer_refresh_timer.cancel()
self._transfer_refresh_timer = None
self._transfer_timeout_timer = Timer()
self._transfer_timeout_timer.schedule(1, <timer_callback>self._transfer_cb_timeout_timer, self)
except PJSIPError, e:
if self._transfer_usage != NULL:
code = 0
reason = e.args[0]
with nogil:
pjsip_evsub_terminate(self._transfer_usage, 0)
# Manually trigger the state callback since we handle the timeout ourselves
state_timer = TransferStateCallbackTimer("TERMINATED", code, reason)
state_timer.schedule(0, <timer_callback>self._transfer_cb_state, self)
cdef int _terminate_transfer_uas(self) except -1:
global sipfrag_re
cdef int code
cdef TransferStateCallbackTimer state_timer
if self.transfer_state == "TERMINATED":
return 0
self._set_transfer_state("TERMINATED")
self._send_notify()
with nogil:
pjsip_evsub_terminate(self._transfer_usage, 0)
match = sipfrag_re.match(self._sipfrag_payload.str)
code = int(match.group('code'))
reason = match.group('reason')
state_timer = TransferStateCallbackTimer("TERMINATED", code, reason)
state_timer.schedule(0, <timer_callback>self._transfer_cb_state, self)
cdef int _set_transfer_state(self, str state) except -1:
cdef str prev_state
prev_state = self.transfer_state
self.transfer_state = state
if prev_state != state:
_add_event("SIPInvitationTransferChangedState", dict(obj=self, prev_state=prev_state, state=state))
cdef int _set_sipfrag_payload(self, int code, str status) except -1:
cdef str content
if status is None:
try:
status = sip_status_messages[code]
except IndexError:
status = "Unknown"
content = "SIP/2.0 %d %s\r\n" % (code, status)
self._sipfrag_payload = PJSTR(content)
cdef int _send_notify(self) except -1:
cdef pjsip_evsub_state state
cdef pj_str_t *reason_p = NULL
cdef pjsip_tx_data *tdata
cdef int status
cdef dict _sipfrag_version = dict(version="2.0")
cdef PJSTR _content_type = PJSTR(b"message")
cdef PJSTR _content_subtype = PJSTR(b"sipfrag")
cdef PJSTR noresource = PJSTR(b"noresource")
cdef PJSTR content
if self.transfer_state == "ACTIVE":
state = PJSIP_EVSUB_STATE_ACTIVE
else:
state = PJSIP_EVSUB_STATE_TERMINATED
reason_p = &noresource.pj_str
with nogil:
status = pjsip_evsub_notify(self._transfer_usage, state, NULL, reason_p, &tdata)
if status != 0:
raise PJSIPError("Could not create NOTIFY request", status)
if self.transfer_state in ("ACTIVE", "TERMINATED"):
tdata.msg.body = pjsip_msg_body_create(tdata.pool, &_content_type.pj_str, &_content_subtype.pj_str, &self._sipfrag_payload.pj_str)
_dict_to_pjsip_param(_sipfrag_version, &tdata.msg.body.content_type.param, tdata.pool)
with nogil:
status = pjsip_evsub_send_request(self._transfer_usage, tdata)
if status != 0:
raise PJSIPError("Could not send NOTIFY request", status)
return 0
cdef int _transfer_cb_timeout_timer(self, timer) except -1:
global sip_status_messages
cdef int code
cdef str reason
cdef int status
cdef TransferStateCallbackTimer state_timer
cdef pj_mutex_t *lock = self._lock
cdef PJSIPUA ua
ua = self._check_ua()
if ua is None:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
if self._transfer_usage != NULL:
code = PJSIP_SC_TSX_TIMEOUT
reason = sip_status_messages[PJSIP_SC_TSX_TIMEOUT]
with nogil:
pjsip_evsub_terminate(self._transfer_usage, 0)
# Manually trigger the state callback since we handle the timeout ourselves
state_timer = TransferStateCallbackTimer("TERMINATED", code, reason)
state_timer.schedule(0, <timer_callback>self._transfer_cb_state, self)
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int _transfer_cb_refresh_timer(self, timer) except -1:
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef PJSIPUA ua
ua = self._check_ua()
if ua is None:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
self._terminate_transfer()
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int _transfer_cb_state(self, TransferStateCallbackTimer timer) except -1:
cdef int status
cdef str prev_state
cdef pj_mutex_t *lock = self._lock
cdef PJSIPUA ua
ua = self._check_ua()
if ua is None:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
prev_state = self.transfer_state
self._set_transfer_state(timer.state)
if timer.state == "ACCEPTED" and prev_state == "SENT":
_add_event("SIPInvitationTransferDidStart", dict(obj=self))
elif timer.state == "TERMINATED":
# If a NOTIFY is rejected with 408 or 481 PJSIP will erase the subscription
if self._transfer_usage != NULL:
pjsip_evsub_set_mod_data(self._transfer_usage, ua._event_module.id, NULL)
if self._transfer_timeout_timer is not None:
self._transfer_timeout_timer.cancel()
self._transfer_timeout_timer = None
if self._transfer_refresh_timer is not None:
self._transfer_refresh_timer.cancel()
self._transfer_refresh_timer = None
self._transfer_usage = NULL
if timer.code/100 == 2:
_add_event("SIPInvitationTransferDidEnd", dict(obj=self))
else:
_add_event("SIPInvitationTransferDidFail", dict(obj=self, code=timer.code, reason=timer.reason))
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int _transfer_cb_response(self, TransferResponseCallbackTimer timer) except -1:
cdef int expires
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef PJSIPUA ua
ua = self._check_ua()
if ua is None:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
if self._transfer_timeout_timer is not None:
self._transfer_timeout_timer.cancel()
self._transfer_timeout_timer = None
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int _transfer_cb_notify(self, TransferRequestCallbackTimer timer) except -1:
cdef pj_time_val refresh
cdef int expires
cdef dict notify_dict = dict(obj=self)
cdef pj_mutex_t *lock = self._lock
cdef PJSIPUA ua
ua = self._check_ua()
if ua is None:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
sub_state_hdr = timer.rdata["headers"].get("Subscription-State", None)
if self.transfer_state != "TERMINATED" and sub_state_hdr is not None and sub_state_hdr.expires > 0:
if self._transfer_refresh_timer is not None:
self._transfer_refresh_timer.cancel()
self._transfer_refresh_timer = None
expires = max(1, sub_state_hdr.expires - self.expire_warning_time, sub_state_hdr.expires/2)
self._transfer_refresh_timer = Timer()
self._transfer_refresh_timer.schedule(expires, <timer_callback>self._transfer_cb_refresh_timer, self)
notify_dict["request_uri"] = timer.rdata["request_uri"]
notify_dict["from_header"] = timer.rdata["headers"].get("From", None)
notify_dict["to_header"] = timer.rdata["headers"].get("To", None)
notify_dict["headers"] = timer.rdata["headers"]
notify_dict["body"] = timer.rdata["body"]
content_type = notify_dict["headers"].get("Content-Type", None)
notify_dict["content_type"] = content_type.content_type if content_type else None
event = notify_dict["headers"].get("Event", None)
notify_dict["event"] = event.event if event else None
_add_event("SIPInvitationTransferGotNotify", notify_dict)
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
cdef int _transfer_cb_server_timeout(self, timer) except -1:
cdef int status
cdef pj_mutex_t *lock = self._lock
cdef PJSIPUA ua
ua = self._check_ua()
if ua is None:
return 0
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
self._terminate_transfer()
finally:
with nogil:
pj_mutex_unlock(lock)
return 0
# Callback functions
#
cdef void _Invitation_cb_state(pjsip_inv_session *inv, pjsip_event *e) with gil:
cdef pjsip_rx_data *rdata = NULL
cdef pjsip_tx_data *tdata = NULL
cdef object state
cdef object rdata_dict = None
cdef object tdata_dict = None
cdef object originator = None
cdef Invitation invitation
cdef PJSIPUA ua
cdef StateCallbackTimer timer
try:
ua = _get_ua()
except:
return
try:
if inv.state == PJSIP_INV_STATE_INCOMING:
return
if inv.mod_data[ua._module.id] != NULL:
invitation = (<object> inv.mod_data[ua._module.id])()
if invitation is None:
return
state = pjsip_inv_state_name(inv.state).decode().lower()
sub_state = None
if state == "calling":
state = "outgoing"
elif state == "confirmed":
state = "connected"
sub_state = "normal"
elif state == "disconnctd":
state = "disconnected"
if e != NULL:
if e.type == PJSIP_EVENT_TSX_STATE and e.body.tsx_state.type == PJSIP_EVENT_TX_MSG:
tdata = e.body.tsx_state.src.tdata
if (tdata.msg.type == PJSIP_RESPONSE_MSG and tdata.msg.line.status.code == 487 and
state == "disconnected" and invitation.state in ["incoming", "early"]):
return
elif e.type == PJSIP_EVENT_RX_MSG:
rdata = e.body.rx_msg.rdata
elif e.type == PJSIP_EVENT_TSX_STATE and e.body.tsx_state.type == PJSIP_EVENT_RX_MSG:
if (inv.state != PJSIP_INV_STATE_CONFIRMED or
e.body.tsx_state.src.rdata.msg_info.msg.type == PJSIP_REQUEST_MSG):
rdata = e.body.tsx_state.src.rdata
elif e.type == PJSIP_EVENT_TSX_STATE and e.body.tsx_state.type == PJSIP_EVENT_TRANSPORT_ERROR and e.body.tsx_state.tsx.role == PJSIP_ROLE_UAC:
# A transport error occurred, fake a local reply
rdata_dict = dict()
rdata_dict["code"] = 408
rdata_dict["reason"] = "Transport Error"
rdata_dict["headers"] = dict()
rdata_dict["body"] = None
originator = "local"
if rdata != NULL:
if invitation.peer_address is None:
invitation.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
invitation.peer_address.ip = rdata.pkt_info.src_name
invitation.peer_address.port = rdata.pkt_info.src_port
rdata_dict = dict()
_pjsip_msg_to_dict(rdata.msg_info.msg, rdata_dict)
originator = "remote"
if tdata != NULL:
tdata_dict = dict()
_pjsip_msg_to_dict(tdata.msg, tdata_dict)
originator = "local"
try:
timer = StateCallbackTimer(state, sub_state, rdata_dict, tdata_dict, originator)
timer.schedule(0, <timer_callback>invitation._cb_state, invitation)
except:
invitation._fail(ua)
except:
ua._handle_exception(1)
cdef void _Invitation_cb_sdp_done(pjsip_inv_session *inv, int status) with gil:
cdef Invitation invitation
cdef PJSIPUA ua
cdef SDPCallbackTimer timer
cdef pjmedia_sdp_session_ptr_const sdp
try:
ua = _get_ua()
except:
return
try:
if inv.mod_data[ua._module.id] != NULL:
invitation = (<object> inv.mod_data[ua._module.id])()
if invitation is None:
return
if status == 0:
if pjmedia_sdp_neg_get_active_local(invitation._invite_session.neg, &sdp) == 0:
local_sdp = SDPSession_create(sdp)
else:
local_sdp = None
if pjmedia_sdp_neg_get_active_remote(invitation._invite_session.neg, &sdp) == 0:
remote_sdp = SDPSession_create(sdp)
else:
remote_sdp = None
if local_sdp is None or remote_sdp is None:
active_local = None
active_remote = None
else:
if len(local_sdp.media) > len(remote_sdp.media):
local_sdp.media = local_sdp.media[:len(remote_sdp.media)]
if len(remote_sdp.media) > len(local_sdp.media):
remote_sdp.media = remote_sdp.media[:len(local_sdp.media)]
for index, local_media in enumerate(local_sdp.media):
remote_media = remote_sdp.media[index]
if not local_media.port and remote_media.port:
remote_media.port = 0
if not remote_media.port and local_media.port:
local_media.port = 0
active_local = FrozenSDPSession.new(local_sdp)
active_remote = FrozenSDPSession.new(remote_sdp)
else:
active_local = None
active_remote = None
try:
timer = SDPCallbackTimer(status, active_local, active_remote)
timer.schedule(0, <timer_callback>invitation._cb_sdp_done, invitation)
except:
invitation._fail(ua)
except:
ua._handle_exception(1)
cdef int _Invitation_cb_rx_reinvite(pjsip_inv_session *inv, pjmedia_sdp_session_ptr_const offer, pjsip_rx_data *rdata) with gil:
cdef int status
cdef pjsip_tx_data *answer_tdata
cdef object rdata_dict = None
cdef Invitation invitation
cdef PJSIPUA ua
cdef StateCallbackTimer timer
try:
ua = _get_ua()
except:
return 1
try:
if inv.mod_data[ua._module.id] != NULL:
invitation = (<object> inv.mod_data[ua._module.id])()
if invitation is None:
return 1
if invitation.peer_address is None:
invitation.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
invitation.peer_address.ip = rdata.pkt_info.src_name
invitation.peer_address.port = rdata.pkt_info.src_port
rdata_dict = dict()
_pjsip_msg_to_dict(rdata.msg_info.msg, rdata_dict)
with nogil:
status = pjsip_inv_initial_answer(inv, rdata, 100, NULL, NULL, &answer_tdata)
if status != 0:
raise PJSIPError("Could not create initial (unused) response to re-INVITE", status)
with nogil:
pjsip_tx_data_dec_ref(answer_tdata)
if offer != NULL:
sub_state = "received_proposal"
else:
sub_state = "received_proposal_request"
try:
timer = StateCallbackTimer("connected", sub_state, rdata_dict, None, "remote")
timer.schedule(0, <timer_callback>invitation._cb_state, invitation)
except:
invitation._fail(ua)
return 1
return 0
except:
ua._handle_exception(1)
return 1
cdef void _Invitation_cb_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) with gil:
cdef pjsip_rx_data *rdata = NULL
cdef pjsip_tx_data *tdata = NULL
cdef object rdata_dict = None
cdef object tdata_dict = None
cdef object originator = None
cdef Invitation invitation
cdef PJSIPUA ua
cdef StateCallbackTimer timer
cdef TransferRequestCallbackTimer transfer_timer
try:
ua = _get_ua()
except:
return
try:
if tsx == NULL or e == NULL:
return
if e.type == PJSIP_EVENT_TSX_STATE and e.body.tsx_state.type == PJSIP_EVENT_RX_MSG:
rdata = e.body.tsx_state.src.rdata
if e.type == PJSIP_EVENT_TSX_STATE and e.body.tsx_state.type == PJSIP_EVENT_TX_MSG:
tdata = e.body.tsx_state.src.tdata
if inv.mod_data[ua._module.id] != NULL:
invitation = (<object> inv.mod_data[ua._module.id])()
if invitation is None:
return
if rdata != NULL:
if invitation.peer_address is None:
invitation.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
invitation.peer_address.ip = rdata.pkt_info.src_name
invitation.peer_address.port = rdata.pkt_info.src_port
if ((tsx.state == PJSIP_TSX_STATE_TERMINATED or tsx.state == PJSIP_TSX_STATE_COMPLETED) and
(inv.neg != NULL and pjmedia_sdp_neg_get_state(inv.neg) in (PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER, PJMEDIA_SDP_NEG_STATE_DONE)) and
invitation._reinvite_transaction != NULL and invitation._reinvite_transaction == tsx):
if rdata != NULL:
rdata_dict = dict()
_pjsip_msg_to_dict(rdata.msg_info.msg, rdata_dict)
originator = "remote"
if tdata != NULL:
tdata_dict = dict()
_pjsip_msg_to_dict(tdata.msg, tdata_dict)
originator = "local"
try:
timer = StateCallbackTimer("connected", "normal", rdata_dict, tdata_dict, originator)
timer.schedule(0, <timer_callback>invitation._cb_state, invitation)
except:
invitation._fail(ua)
elif (invitation.state in ("incoming", "early") and invitation.direction == "incoming" and
rdata != NULL and rdata.msg_info.msg.type == PJSIP_REQUEST_MSG and
rdata.msg_info.msg.line.req.method.id == PJSIP_CANCEL_METHOD):
rdata_dict = dict()
_pjsip_msg_to_dict(rdata.msg_info.msg, rdata_dict)
originator = "remote"
try:
timer = StateCallbackTimer("disconnected", None, rdata_dict, None, originator)
timer.schedule(0, <timer_callback>invitation._cb_state, invitation)
except:
invitation._fail(ua)
elif (tsx.role == PJSIP_ROLE_UAS and tsx.state == PJSIP_TSX_STATE_TRYING and
rdata != NULL and rdata.msg_info.msg.type == PJSIP_REQUEST_MSG and
_pj_str_to_str(tsx.method.name) == "REFER"):
invitation.process_incoming_transfer(ua, rdata)
elif (tsx.role == PJSIP_ROLE_UAS and tsx.state == PJSIP_TSX_STATE_TRYING and
rdata != NULL and rdata.msg_info.msg.type == PJSIP_REQUEST_MSG and tsx.method.id == PJSIP_OPTIONS_METHOD):
invitation.process_incoming_options(ua, rdata)
except:
ua._handle_exception(1)
cdef void _Invitation_cb_new(pjsip_inv_session *inv, pjsip_event *e) with gil:
# As far as I can tell this is never actually called!
pass
cdef void _Invitation_transfer_cb_state(pjsip_evsub *sub, pjsip_event *event) with gil:
cdef void *invitation_void
cdef Invitation invitation
cdef object state
cdef int code = 0
cdef dict event_dict = dict()
cdef str reason = None
cdef pjsip_rx_data *rdata = NULL
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
invitation_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if invitation_void == NULL:
return
invitation = (<object> invitation_void)()
if invitation is None:
return
state = pjsip_evsub_get_state_name(sub)
if (event != NULL and event.type == PJSIP_EVENT_TSX_STATE and
(event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_COMPLETED or
event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_TERMINATED)):
if state == "TERMINATED":
if event.body.tsx_state.tsx.role == PJSIP_ROLE_UAC:
code = event.body.tsx_state.tsx.status_code
reason = _pj_str_to_str(event.body.tsx_state.tsx.status_text)
else:
reason = "Referral has expired"
if event.body.tsx_state.type == PJSIP_EVENT_RX_MSG and _pj_str_to_str(event.body.tsx_state.tsx.method.name) == "NOTIFY":
# Extract code and reason from the sipfrag payload
rdata = event.body.tsx_state.src.rdata
if rdata != NULL:
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
if event_dict.get('body', None) is not None:
match = sipfrag_re.match(event_dict['body'])
if match:
code = int(match.group('code'))
reason = match.group('reason')
try:
timer = TransferStateCallbackTimer(state, code, reason)
timer.schedule(0, <timer_callback>invitation._transfer_cb_state, invitation)
except:
invitation._fail(ua)
except:
ua._handle_exception(1)
cdef void _Invitation_transfer_cb_tsx(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) with gil:
cdef void *invitation_void
cdef Invitation invitation
cdef pjsip_rx_data *rdata
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
invitation_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if invitation_void == NULL:
return
invitation = (<object> invitation_void)()
if invitation is None:
return
if (event != NULL and event.type == PJSIP_EVENT_TSX_STATE and
event.body.tsx_state.type == PJSIP_EVENT_RX_MSG and
event.body.tsx_state.tsx.role == PJSIP_ROLE_UAC and
event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_COMPLETED and
_pj_str_to_str(event.body.tsx_state.tsx.method.name) in ("REFER", "SUBSCRIBE") and
event.body.tsx_state.tsx.status_code/100 == 2):
rdata = event.body.tsx_state.src.rdata
if rdata != NULL:
rdata_dict = dict()
_pjsip_msg_to_dict(rdata.msg_info.msg, rdata_dict)
try:
timer = TransferResponseCallbackTimer(_pj_str_to_bytes(event.body.tsx_state.tsx.method.name), rdata_dict)
timer.schedule(0, <timer_callback>invitation._transfer_cb_response, invitation)
except:
invitation._fail(ua)
except:
ua._handle_exception(1)
cdef void _Invitation_transfer_cb_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil:
cdef void *invitation_void
cdef Invitation invitation
cdef TransferRequestCallbackTimer timer
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
invitation_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if invitation_void == NULL:
return
invitation = (<object> invitation_void)()
if invitation is None:
return
if rdata != NULL:
rdata_dict = dict()
_pjsip_msg_to_dict(rdata.msg_info.msg, rdata_dict)
try:
timer = TransferRequestCallbackTimer(rdata_dict)
timer.schedule(0, <timer_callback>invitation._transfer_cb_notify, invitation)
except:
invitation._fail(ua)
except:
ua._handle_exception(1)
cdef void _Invitation_transfer_cb_refresh(pjsip_evsub *sub) with gil:
# We want to handle the refresh timer oursevles, ignore the PJSIP provided timer
pass
cdef void _Invitation_transfer_in_cb_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil:
cdef void *invitation_void
cdef dict rdata_dict
cdef pjsip_expires_hdr *expires_header
cdef Invitation invitation
cdef Timer timer
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
invitation_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if invitation_void == NULL:
p_st_code[0] = 481
return
invitation = (<object> invitation_void)()
if invitation is None:
p_st_code[0] = 481
return
expires_header = <pjsip_expires_hdr *> pjsip_msg_find_hdr(rdata.msg_info.msg, PJSIP_H_EXPIRES, NULL)
if expires_header != NULL and expires_header.ivalue == 0:
try:
timer = Timer()
timer.schedule(0, <timer_callback>invitation._terminate_transfer, invitation)
except:
invitation._fail(ua)
p_st_code[0] = 200
return
p_st_code[0] = 501
except:
ua._handle_exception(1)
cdef void _Invitation_transfer_in_cb_server_timeout(pjsip_evsub *sub) with gil:
cdef void *invitation_void
cdef Invitation invitation
cdef Timer timer
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
invitation_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if invitation_void == NULL:
return
invitation = (<object> invitation_void)()
if invitation is None:
return
try:
timer = Timer()
timer.schedule(0, <timer_callback>invitation._transfer_cb_server_timeout, invitation)
except:
invitation._fail(ua)
except:
ua._handle_exception(1)
cdef void _Invitation_transfer_in_cb_tsx(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) with gil:
cdef void *invitation_void
cdef Invitation invitation
cdef PJSIPUA ua
cdef pjsip_rx_data *rdata
cdef dict event_dict
cdef int code
cdef str reason
cdef TransferStateCallbackTimer timer
try:
ua = _get_ua()
except:
return
try:
invitation_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if invitation_void == NULL:
return
invitation = (<object> invitation_void)()
if invitation is None:
return
if (event != NULL and event.type == PJSIP_EVENT_TSX_STATE and event.body.tsx_state.tsx.role == PJSIP_ROLE_UAC and
_pj_str_to_str(event.body.tsx_state.tsx.method.name) == "NOTIFY" and
event.body.tsx_state.tsx.state in (PJSIP_TSX_STATE_COMPLETED, PJSIP_TSX_STATE_TERMINATED)):
code = event.body.tsx_state.tsx.status_code
reason = _pj_str_to_str(event.body.tsx_state.tsx.status_text)
if code in (408, 481) or code/100==7:
# Be careful! PJSIP will erase the subscription
timer = TransferStateCallbackTimer("TERMINATED", code, reason)
timer.schedule(0, <timer_callback>invitation._transfer_cb_state, invitation)
except:
ua._handle_exception(1)
# Globals
#
cdef pjsip_inv_callback _inv_cb
_inv_cb.on_state_changed = _Invitation_cb_state
_inv_cb.on_media_update = _Invitation_cb_sdp_done
_inv_cb.on_rx_reinvite = _Invitation_cb_rx_reinvite
_inv_cb.on_tsx_state_changed = _Invitation_cb_tsx_state_changed
_inv_cb.on_new_session = _Invitation_cb_new
cdef pjsip_evsub_user _transfer_cb
_transfer_cb.on_evsub_state = _Invitation_transfer_cb_state
_transfer_cb.on_tsx_state = _Invitation_transfer_cb_tsx
_transfer_cb.on_rx_notify = _Invitation_transfer_cb_notify
_transfer_cb.on_client_refresh = _Invitation_transfer_cb_refresh
cdef pjsip_evsub_user _incoming_transfer_cb
_incoming_transfer_cb.on_rx_refresh = _Invitation_transfer_in_cb_rx_refresh
_incoming_transfer_cb.on_server_timeout = _Invitation_transfer_in_cb_server_timeout
_incoming_transfer_cb.on_tsx_state = _Invitation_transfer_in_cb_tsx
diff --git a/sipsimple/core/_core.pxd b/sipsimple/core/_core.pxd
index d798c2f3..7aa4766b 100644
--- a/sipsimple/core/_core.pxd
+++ b/sipsimple/core/_core.pxd
@@ -1,2640 +1,2645 @@
# cython: language_level=2
cdef extern from *:
ctypedef char *char_ptr_const "const char *"
enum:
PJ_SVN_REV "PJ_SVN_REVISION"
# system imports
from libc.stdlib cimport malloc, free
from libc.string cimport memcpy
# Python C imports
from cpython.float cimport PyFloat_AsDouble
from cpython.ref cimport Py_INCREF, Py_DECREF
from cpython.bytes cimport PyBytes_FromString, PyBytes_FromStringAndSize, PyBytes_AsString, PyBytes_Size
cdef extern from "Python.h":
object PyUnicode_FromString(const char *u)
# PJSIP imports
cdef extern from "pjlib.h":
# constants
enum:
PJ_ERR_MSG_SIZE
enum:
PJ_ERRNO_START_SYS
PJ_EBUG
PJ_ETOOMANY
enum:
PJ_MAX_OBJ_NAME
# init / shutdown
int pj_init() nogil
void pj_shutdown() nogil
# version
char *pj_get_version() nogil
# string
struct pj_str_t:
char *ptr
int slen
ctypedef pj_str_t *pj_str_ptr_const "const pj_str_t *"
# errors
pj_str_t pj_strerror(int statcode, char *buf, int bufsize) nogil
# logging
enum:
PJ_LOG_MAX_LEVEL
enum pj_log_decoration:
PJ_LOG_HAS_YEAR
PJ_LOG_HAS_MONTH
PJ_LOG_HAS_DAY_OF_MON
PJ_LOG_HAS_TIME
PJ_LOG_HAS_MICRO_SEC
PJ_LOG_HAS_SENDER
PJ_LOG_HAS_INDENT
void pj_log_set_decor(int decor) nogil
int pj_log_get_level() nogil
void pj_log_set_level(int level) nogil
void pj_log_set_log_func(void func(int level, char_ptr_const data, int len)) nogil
# memory management
struct pj_pool_t
struct pj_pool_factory_policy:
pass
pj_pool_factory_policy pj_pool_factory_default_policy
struct pj_pool_factory:
pass
struct pj_caching_pool:
pj_pool_factory factory
void pj_caching_pool_init(pj_caching_pool *ch_pool, pj_pool_factory_policy *policy, int max_capacity) nogil
void pj_caching_pool_destroy(pj_caching_pool *ch_pool) nogil
void *pj_pool_alloc(pj_pool_t *pool, int size) nogil
void pj_pool_reset(pj_pool_t *pool) nogil
pj_pool_t *pj_pool_create_on_buf(char *name, void *buf, int size) nogil
pj_str_t *pj_strdup2_with_null(pj_pool_t *pool, pj_str_t *dst, char *src) nogil
void pj_pool_release(pj_pool_t *pool) nogil
# threads
enum:
PJ_THREAD_DESC_SIZE
struct pj_mutex_t
struct pj_rwmutex_t
struct pj_thread_t
int pj_mutex_create_simple(pj_pool_t *pool, char *name, pj_mutex_t **mutex) nogil
int pj_mutex_create_recursive(pj_pool_t *pool, char *name, pj_mutex_t **mutex) nogil
int pj_mutex_lock(pj_mutex_t *mutex) nogil
int pj_mutex_unlock(pj_mutex_t *mutex) nogil
int pj_mutex_destroy(pj_mutex_t *mutex) nogil
int pj_rwmutex_create(pj_pool_t *pool, char *name, pj_rwmutex_t **mutex) nogil
int pj_rwmutex_lock_read(pj_rwmutex_t *mutex) nogil
int pj_rwmutex_lock_write(pj_rwmutex_t *mutex) nogil
int pj_rwmutex_unlock_read(pj_rwmutex_t *mutex) nogil
int pj_rwmutex_unlock_write(pj_rwmutex_t *mutex) nogil
int pj_rwmutex_destroy(pj_rwmutex_t *mutex) nogil
int pj_thread_is_registered() nogil
int pj_thread_register(char *thread_name, long *thread_desc, pj_thread_t **thread) nogil
# sockets
enum:
PJ_INET6_ADDRSTRLEN
struct pj_ioqueue_t
struct pj_addr_hdr:
unsigned int sa_family
struct pj_sockaddr_in:
pass
struct pj_sockaddr_in6:
pass
ctypedef union pj_sockaddr:
pj_addr_hdr addr
pj_sockaddr_in ipv4
pj_sockaddr_in6 ipv6
ctypedef pj_sockaddr *pj_sockaddr_ptr_const "const pj_sockaddr *"
int pj_AF_INET() nogil
int pj_AF_INET6() nogil
int pj_sockaddr_in_init(pj_sockaddr_in *addr, pj_str_t *cp, int port) nogil
int pj_sockaddr_get_port(pj_sockaddr *addr) nogil
char *pj_sockaddr_print(pj_sockaddr *addr, char *buf, int size, unsigned int flags) nogil
int pj_sockaddr_has_addr(pj_sockaddr *addr) nogil
int pj_sockaddr_init(int af, pj_sockaddr *addr, pj_str_t *cp, unsigned int port) nogil
int pj_inet_pton(int af, pj_str_t *src, void *dst) nogil
# dns
struct pj_dns_resolver
int pj_dns_resolver_set_ns(pj_dns_resolver *resolver, unsigned count, pj_str_t *servers, int *ports) nogil
# time
struct pj_time_val:
long sec
long msec
void pj_gettimeofday(pj_time_val *tv) nogil
void pj_time_val_normalize(pj_time_val *tv) nogil
# timers
struct pj_timer_heap_t
struct pj_timer_entry:
void *user_data
int id
pj_timer_entry *pj_timer_entry_init(pj_timer_entry *entry, int id, void *user_data,
void cb(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) with gil) nogil
# lists
struct pj_list:
void *prev
void *next
void pj_list_init(pj_list *node) nogil
void pj_list_insert_after(pj_list *pos, pj_list *node) nogil
# random
void pj_srand(unsigned int seed) nogil
# maths
struct pj_math_stat:
int n
int max
int min
int last
int mean
cdef extern from "pjlib-util.h":
# init
int pjlib_util_init() nogil
cdef extern from "pjnath.h":
# init
int pjnath_init() nogil
# STUN
enum:
PJ_STUN_PORT
struct pj_stun_config:
pass
struct pj_stun_sock_cfg:
pj_sockaddr bound_addr
void pj_stun_config_init(pj_stun_config *cfg, pj_pool_factory *factory, unsigned int options,
pj_ioqueue_t *ioqueue, pj_timer_heap_t *timer_heap) nogil
# NAT detection
struct pj_stun_nat_detect_result:
int status
char *status_text
char *nat_type_name
ctypedef pj_stun_nat_detect_result *pj_stun_nat_detect_result_ptr_const "const pj_stun_nat_detect_result *"
int pj_stun_detect_nat_type(pj_sockaddr_in *server, pj_stun_config *stun_cfg, void *user_data,
void pj_stun_nat_detect_cb(void *user_data,
pj_stun_nat_detect_result_ptr_const res) with gil) nogil
# ICE
struct pj_ice_strans
struct pj_ice_sess_cand:
int type
int comp_id
int prio
pj_sockaddr addr
pj_sockaddr rel_addr
struct pj_ice_sess_check:
pj_ice_sess_cand *lcand
pj_ice_sess_cand *rcand
int state
int nominated
ctypedef pj_ice_sess_check *pj_ice_sess_check_ptr_const "const pj_ice_sess_check *"
struct pj_ice_sess_comp:
pj_ice_sess_check *valid_check
struct pj_ice_sess_checklist:
int count
pj_ice_sess_check *checks
struct pj_ice_sess:
int comp_cnt
pj_ice_sess_comp *comp
int lcand_cnt
pj_ice_sess_cand *lcand
int rcand_cnt
pj_ice_sess_cand *rcand
pj_ice_sess_checklist valid_list
struct pj_ice_strans_cfg_stun:
pj_stun_sock_cfg cfg
pj_str_t server
unsigned int port
struct pj_ice_strans_cfg:
int af
pj_stun_config stun_cfg
pj_ice_strans_cfg_stun stun
enum pj_ice_strans_op:
PJ_ICE_STRANS_OP_INIT
PJ_ICE_STRANS_OP_NEGOTIATION
enum pj_ice_strans_state:
PJ_ICE_STRANS_STATE_NULL
PJ_ICE_STRANS_STATE_INIT
PJ_ICE_STRANS_STATE_READY
PJ_ICE_STRANS_STATE_SESS_READY
PJ_ICE_STRANS_STATE_NEGO
PJ_ICE_STRANS_STATE_RUNNING
PJ_ICE_STRANS_STATE_FAILED
enum pj_ice_cand_type:
PJ_ICE_CAND_TYPE_HOST
PJ_ICE_CAND_TYPE_SRFLX
PJ_ICE_CAND_TYPE_PRFLX
PJ_ICE_CAND_TYPE_RELAYED
enum pj_ice_sess_check_state:
PJ_ICE_SESS_CHECK_STATE_FROZEN
PJ_ICE_SESS_CHECK_STATE_WAITING
PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS
PJ_ICE_SESS_CHECK_STATE_SUCCEEDED
PJ_ICE_SESS_CHECK_STATE_FAILED
struct pjmedia_ice_transport_info:
int active
pj_ice_strans_state sess_state
void pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg) nogil
pj_ice_sess* pj_ice_strans_get_session(pj_ice_strans *ice_st)
pj_time_val pj_ice_strans_get_start_time(pj_ice_strans *ice_st)
pj_ice_strans_state pj_ice_strans_get_state(pj_ice_strans *ice_st)
pj_ice_sess_check_ptr_const pj_ice_strans_get_valid_pair(pj_ice_strans *ice_st, unsigned comp_id)
cdef extern from "pjmedia.h":
enum:
PJMEDIA_ENOSNDREC
PJMEDIA_ENOSNDPLAY
enum:
PJMEDIA_AUD_DEFAULT_CAPTURE_DEV
PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV
PJMEDIA_AUD_DEV_CAP_EC
PJMEDIA_AUD_DEV_CAP_EC_TAIL
enum:
PJMEDIA_VID_DEFAULT_CAPTURE_DEV
PJMEDIA_VID_DEFAULT_RENDER_DEV
PJMEDIA_VID_INVALID_DEV
enum pjmedia_dir:
PJMEDIA_DIR_NONE
PJMEDIA_DIR_ENCODING
PJMEDIA_DIR_DECODING
PJMEDIA_DIR_ENCODING_DECODING
PJMEDIA_DIR_PLAYBACK = PJMEDIA_DIR_DECODING
PJMEDIA_DIR_RENDER = PJMEDIA_DIR_DECODING
PJMEDIA_DIR_CAPTURE = PJMEDIA_DIR_ENCODING
PJMEDIA_DIR_CAPTURE_PLAYBACK = PJMEDIA_DIR_ENCODING_DECODING
PJMEDIA_DIR_CAPTURE_RENDER = PJMEDIA_DIR_ENCODING_DECODING
enum pjmedia_type:
PJMEDIA_TYPE_NONE
PJMEDIA_TYPE_NONEYPE_AUDIO
PJMEDIA_TYPE_VIDEO
PJMEDIA_TYPE_APPLICATION
PJMEDIA_TYPE_UNKNOWN
struct pjmedia_rect_size:
unsigned int w
unsigned int h
struct pjmedia_ratio:
int num
int denum
# frame
struct pjmedia_frame:
void *buf
int size
ctypedef pjmedia_frame *pjmedia_frame_ptr_const "const pjmedia_frame *"
# codec manager
struct pjmedia_codec_mgr
enum:
PJMEDIA_CODEC_MGR_MAX_CODECS
struct pjmedia_codec_info:
pj_str_t encoding_name
unsigned int clock_rate
unsigned int channel_cnt
int pjmedia_codec_mgr_enum_codecs(pjmedia_codec_mgr *mgr, unsigned int *count, pjmedia_codec_info *info, unsigned int *prio) nogil
int pjmedia_codec_mgr_set_codec_priority(pjmedia_codec_mgr *mgr, pj_str_t *codec_id, unsigned int prio) nogil
# transport manager
struct pjsip_tpmgr
struct pjsip_transport_state_info:
int status
enum pjsip_transport_state:
PJSIP_TP_STATE_CONNECTED
PJSIP_TP_STATE_DISCONNECTED
ctypedef pjsip_transport_state_info *pjsip_transport_state_info_ptr_const "const pjsip_transport_state_info *"
ctypedef void (*pjsip_tp_state_callback)(pjsip_transport *tp, pjsip_transport_state state, pjsip_transport_state_info_ptr_const info) with gil
int pjsip_tpmgr_set_state_cb(pjsip_tpmgr *mgr, pjsip_tp_state_callback cb)
# formats
enum pjmedia_format_detail_type:
PJMEDIA_FORMAT_DETAIL_NONE
PJMEDIA_FORMAT_DETAIL_AUDIO
PJMEDIA_FORMAT_DETAIL_VIDEO
PJMEDIA_FORMAT_DETAIL_MAX
struct pjmedia_audio_format_detail:
unsigned int clock_rate
unsigned int channel_count
unsigned int frame_time_usec
unsigned int baseits_per_sample
unsigned int avg_bps
unsigned int max_bps
struct pjmedia_video_format_detail:
pjmedia_rect_size size
pjmedia_ratio fps
unsigned int avg_bps
unsigned int max_bps
cdef union pjmedia_format_union:
pjmedia_audio_format_detail aud
pjmedia_video_format_detail vid
char user[1]
struct pjmedia_format:
unsigned int id
pjmedia_type type
pjmedia_format_detail_type detail_type
pjmedia_format_union det
ctypedef pjmedia_format *pjmedia_format_ptr_const "const pjmedia_format *"
enum:
PJMEDIA_CODEC_MAX_FMTP_CNT
struct _param:
pj_str_t name
pj_str_t val
struct pjmedia_codec_fmtp:
int cnt
_param param[PJMEDIA_CODEC_MAX_FMTP_CNT]
# video codec parameters
enum pjmedia_vid_packing:
PJMEDIA_VID_PACKING_PACKETS
struct pjmedia_vid_codec_param:
pjmedia_dir dir
pjmedia_vid_packing packing
pjmedia_format enc_fmt
pjmedia_codec_fmtp enc_fmtp
pjmedia_format dec_fmt
pjmedia_codec_fmtp dec_fmtp
ctypedef pjmedia_vid_codec_param *pjmedia_vid_codec_param_ptr_const "const pjmedia_vid_codec_param *"
# video codec manager
enum:
PJMEDIA_VID_CODEC_MGR_MAX_CODECS
struct pjmedia_vid_codec_info:
pj_str_t encoding_name
unsigned int pt
unsigned int clock_rate
unsigned int packings
ctypedef pjmedia_vid_codec_info *pjmedia_vid_codec_info_ptr_const "const pjmedia_vid_codec_info *"
struct pjmedia_vid_codec_mgr
int pjmedia_vid_codec_mgr_create(pj_pool_t *pool, pjmedia_vid_codec_mgr **mgr) nogil
void pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr *mgr) nogil
pjmedia_vid_codec_mgr* pjmedia_vid_codec_mgr_instance() nogil
int pjmedia_vid_codec_mgr_enum_codecs(pjmedia_vid_codec_mgr *mgr, unsigned int *count, pjmedia_vid_codec_info *info, unsigned int *prio) nogil
int pjmedia_vid_codec_mgr_set_codec_priority(pjmedia_vid_codec_mgr *mgr, pj_str_t *codec_id, unsigned int prio) nogil
int pjmedia_vid_codec_mgr_get_default_param(pjmedia_vid_codec_mgr *mgr, pjmedia_vid_codec_info_ptr_const info, pjmedia_vid_codec_param *param) nogil
int pjmedia_vid_codec_mgr_set_default_param(pjmedia_vid_codec_mgr *mgr, pjmedia_vid_codec_info_ptr_const info, pjmedia_vid_codec_param_ptr_const param) nogil
# video format manager
struct pjmedia_video_format_mgr
int pjmedia_video_format_mgr_create(pj_pool_t *pool, unsigned int max_fmt, unsigned int options, pjmedia_video_format_mgr **p_mgr) nogil
void pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr *mgr) nogil
pjmedia_video_format_mgr* pjmedia_video_format_mgr_instance() nogil
# converter manager
struct pjmedia_converter_mgr
int pjmedia_converter_mgr_create(pj_pool_t *pool, pjmedia_converter_mgr **mgr) nogil
void pjmedia_converter_mgr_destroy(pjmedia_converter_mgr *mgr) nogil
pjmedia_converter_mgr* pjmedia_converter_mgr_instance() nogil
# event manager
struct pjmedia_event_mgr
enum pjmedia_event_type:
PJMEDIA_EVENT_FMT_CHANGED
PJMEDIA_EVENT_KEYFRAME_FOUND
PJMEDIA_EVENT_KEYFRAME_MISSING
PJMEDIA_EVENT_KEYFRAME_REQUESTED
struct pjmedia_event_fmt_changed_data:
pjmedia_dir dir
pjmedia_format new_fmt
cdef union pjmedia_event_data_union:
pjmedia_event_fmt_changed_data fmt_changed
void* ptr
struct pjmedia_event:
pjmedia_event_type type
pjmedia_event_data_union data
int pjmedia_event_mgr_create(pj_pool_t *pool, unsigned int options, pjmedia_event_mgr **mgr) nogil
void pjmedia_event_mgr_destroy(pjmedia_event_mgr *mgr) nogil
pjmedia_event_mgr* pjmedia_event_mgr_instance() nogil
ctypedef int pjmedia_event_cb(pjmedia_event *event, void *user_data)
int pjmedia_event_subscribe(pjmedia_event_mgr *mgr, pjmedia_event_cb *cb, void *user_data, void *epub) nogil
int pjmedia_event_unsubscribe(pjmedia_event_mgr *mgr, pjmedia_event_cb *cb, void *user_data, void *epub) nogil
# endpoint
struct pjmedia_endpt
int pjmedia_endpt_create(pj_pool_factory *pf, pj_ioqueue_t *ioqueue, int worker_cnt, pjmedia_endpt **p_endpt) nogil
pj_pool_t *pjmedia_endpt_create_pool(pjmedia_endpt *endpt, char *pool_name, int initial, int increment) nogil
int pjmedia_endpt_destroy(pjmedia_endpt *endpt) nogil
pj_ioqueue_t *pjmedia_endpt_get_ioqueue(pjmedia_endpt *endpt) nogil
pjmedia_codec_mgr *pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt) nogil
pjsip_tpmgr* pjsip_endpt_get_tpmgr(pjsip_endpoint *endpt)
# sound devices
struct pjmedia_aud_dev_info:
char *name
int input_count
int output_count
struct pjmedia_aud_param:
pjmedia_dir dir
int play_id
int rec_id
int clock_rate
int channel_count
int samples_per_frame
int bits_per_sample
int flags
int ec_enabled
int ec_tail_ms
struct pjmedia_aud_stream
int pjmedia_aud_dev_count() nogil
int pjmedia_aud_dev_get_info(int index, pjmedia_aud_dev_info *info) nogil
int pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm, pjmedia_aud_param *param) nogil
enum pjmedia_aud_dev_event:
PJMEDIA_AUD_DEV_DEFAULT_INPUT_CHANGED
PJMEDIA_AUD_DEV_DEFAULT_OUTPUT_CHANGED
PJMEDIA_AUD_DEV_LIST_WILL_REFRESH
PJMEDIA_AUD_DEV_LIST_DID_REFRESH
ctypedef void (*pjmedia_aud_dev_observer_callback)(pjmedia_aud_dev_event event)
int pjmedia_aud_dev_set_observer_cb(pjmedia_aud_dev_observer_callback cb) nogil
int pjmedia_aud_dev_default_param(int index, pjmedia_aud_param *param) nogil
int pjmedia_aud_dev_refresh() nogil
# sound port
struct pjmedia_port_info:
pjmedia_format fmt
struct pjmedia_port:
pjmedia_port_info info
struct pjmedia_snd_port
struct pjmedia_snd_port_param:
pjmedia_aud_param base
ctypedef pjmedia_snd_port_param *pjmedia_snd_port_param_ptr_const "const pjmedia_snd_port_param *"
int pjmedia_snd_port_create2(pj_pool_t *pool, pjmedia_snd_port_param_ptr_const prm, pjmedia_snd_port **p_port) nogil
void pjmedia_snd_port_param_default(pjmedia_snd_port_param *prm)
int pjmedia_snd_port_connect(pjmedia_snd_port *snd_port, pjmedia_port *port) nogil
int pjmedia_snd_port_disconnect(pjmedia_snd_port *snd_port) nogil
int pjmedia_snd_port_set_ec(pjmedia_snd_port *snd_port, pj_pool_t *pool, unsigned int tail_ms, int options) nogil
int pjmedia_snd_port_reset_ec_state(pjmedia_snd_port *snd_port) nogil
int pjmedia_snd_port_destroy(pjmedia_snd_port *snd_port) nogil
pjmedia_aud_stream *pjmedia_snd_port_get_snd_stream(pjmedia_snd_port *snd_port) nogil
int pjmedia_null_port_create(pj_pool_t *pool, unsigned int sampling_rate, unsigned int channel_count,
unsigned int samples_per_frame, unsigned int bits_per_sample, pjmedia_port **p_port) nogil
int pjmedia_mixer_port_create(pj_pool_t *pool, unsigned int sampling_rate, unsigned int channel_count,
unsigned int samples_per_frame, unsigned int bits_per_sample, pjmedia_port **p_port) nogil
# master port
struct pjmedia_master_port
int pjmedia_master_port_create(pj_pool_t *pool, pjmedia_port *u_port, pjmedia_port *d_port,
unsigned int options, pjmedia_master_port **p_m) nogil
int pjmedia_master_port_start(pjmedia_master_port *m) nogil
int pjmedia_master_port_destroy(pjmedia_master_port *m, int destroy_ports) nogil
# conference bridge
enum pjmedia_conf_option:
PJMEDIA_CONF_NO_DEVICE
struct pjmedia_conf
int pjmedia_conf_create(pj_pool_t *pool, int max_slots, int sampling_rate, int channel_count,
int samples_per_frame, int bits_per_sample, int options, pjmedia_conf **p_conf) nogil
int pjmedia_conf_destroy(pjmedia_conf *conf) nogil
pjmedia_port *pjmedia_conf_get_master_port(pjmedia_conf *conf) nogil
int pjmedia_conf_add_port(pjmedia_conf *conf, pj_pool_t *pool, pjmedia_port *strm_port,
pj_str_t *name, unsigned int *p_slot) nogil
int pjmedia_conf_remove_port(pjmedia_conf *conf, unsigned int slot) nogil
int pjmedia_conf_connect_port(pjmedia_conf *conf, unsigned int src_slot, unsigned int sink_slot, int level) nogil
int pjmedia_conf_disconnect_port(pjmedia_conf *conf, unsigned int src_slot, unsigned int sink_slot) nogil
int pjmedia_conf_adjust_rx_level(pjmedia_conf *conf, unsigned slot, int adj_level) nogil
int pjmedia_conf_adjust_tx_level(pjmedia_conf *conf, unsigned slot, int adj_level) nogil
# video devices
enum pjmedia_vid_dev_cap:
PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE
PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE
PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS
enum pjmedia_vid_dev_wnd_flag:
PJMEDIA_VID_DEV_WND_BORDER
PJMEDIA_VID_DEV_WND_RESIZABLE
struct pjmedia_vid_dev_info:
int id
char *name
char *driver
int dir
cdef struct pjmedia_hwnd_win:
void *hwnd
cdef struct pjmedia_hwnd_x11:
void *window
void *display
cdef struct pjmedia_hwnd_cocoa:
void *window
cdef struct pjmedia_hwnd_ios:
void *window
cdef union pjmedia_hwnd_union:
pjmedia_hwnd_win win
pjmedia_hwnd_x11 x11
pjmedia_hwnd_cocoa cocoa
pjmedia_hwnd_ios ios
void *window
struct pjmedia_vid_dev_hwnd:
pjmedia_hwnd_union info
struct pjmedia_vid_dev_param:
pjmedia_dir dir
int cap_id
int rend_id
unsigned int flags
pjmedia_format fmt
pjmedia_vid_dev_hwnd window
pjmedia_rect_size disp_size
int window_hide
unsigned int window_flags
struct pjmedia_vid_dev_stream
int pjmedia_vid_dev_count() nogil
int pjmedia_vid_dev_get_info(int index, pjmedia_vid_dev_info *info) nogil
int pjmedia_vid_dev_subsys_init(pj_pool_factory *pf) nogil
int pjmedia_vid_dev_subsys_shutdown() nogil
int pjmedia_vid_dev_default_param(pj_pool_t *pool, int id, pjmedia_vid_dev_param *param) nogil
int pjmedia_vid_dev_stream_get_cap(pjmedia_vid_dev_stream *strm, pjmedia_vid_dev_cap cap, void *value) nogil
int pjmedia_vid_dev_stream_set_cap(pjmedia_vid_dev_stream *strm, pjmedia_vid_dev_cap cap, void *value) nogil
int pjmedia_vid_dev_stream_get_param(pjmedia_vid_dev_stream *strm, pjmedia_vid_dev_param *param) nogil
int pjmedia_vid_dev_refresh() nogil
int pjmedia_vid_dev_lookup(char_ptr_const drv_name, char_ptr_const dev_name, int *id)
# video stream
struct pjmedia_vid_stream_info:
pjmedia_vid_codec_param *codec_param
pjmedia_vid_codec_info codec_info
int use_ka
struct pjmedia_vid_stream
ctypedef pjmedia_vid_stream *pjmedia_vid_stream_ptr_const "const pjmedia_vid_stream *"
int pjmedia_vid_stream_get_stat(pjmedia_vid_stream_ptr_const stream, pjmedia_rtcp_stat *stat) nogil
int pjmedia_vid_stream_get_info(pjmedia_vid_stream_ptr_const stream, pjmedia_vid_stream_info *info) nogil
int pjmedia_vid_stream_info_from_sdp(pjmedia_vid_stream_info *si, pj_pool_t *pool, pjmedia_endpt *endpt,
pjmedia_sdp_session *local, pjmedia_sdp_session *remote, unsigned int stream_idx) nogil
int pjmedia_vid_stream_create(pjmedia_endpt *endpt, pj_pool_t *pool, pjmedia_vid_stream_info *info,
pjmedia_transport *tp, void *user_data, pjmedia_vid_stream **p_stream) nogil
int pjmedia_vid_stream_start(pjmedia_vid_stream *stream) nogil
int pjmedia_vid_stream_destroy(pjmedia_vid_stream *stream) nogil
int pjmedia_vid_stream_get_port(pjmedia_vid_stream *stream, pjmedia_dir dir, pjmedia_port **p_port) nogil
int pjmedia_vid_stream_pause(pjmedia_vid_stream *stream, pjmedia_dir dir) nogil
int pjmedia_vid_stream_resume(pjmedia_vid_stream *stream, pjmedia_dir dir) nogil
int pjmedia_vid_stream_send_keyframe(pjmedia_vid_stream *stream) nogil
int pjmedia_vid_stream_send_rtcp_sdes(pjmedia_vid_stream *stream) nogil
int pjmedia_vid_stream_send_rtcp_bye(pjmedia_vid_stream *stream) nogil
int pjmedia_vid_stream_send_rtcp_pli(pjmedia_vid_stream *stream) nogil
# video port
struct pjmedia_vid_port
struct pjmedia_vid_port_param:
pjmedia_vid_dev_param vidparam
int active
void pjmedia_vid_port_param_default(pjmedia_vid_port_param *prm) nogil
ctypedef pjmedia_vid_port_param *pjmedia_vid_port_param_ptr_const "const pjmedia_vid_port_param *"
int pjmedia_vid_port_create(pj_pool_t *pool, pjmedia_vid_port_param_ptr_const prm, pjmedia_vid_port **p_vp) nogil
int pjmedia_vid_port_start(pjmedia_vid_port *vid_port) nogil
int pjmedia_vid_port_is_running(pjmedia_vid_port *vid_port) nogil
int pjmedia_vid_port_stop(pjmedia_vid_port *vid_port) nogil
int pjmedia_vid_port_connect(pjmedia_vid_port *vid_port, pjmedia_port *port, int destroy) nogil
pjmedia_port *pjmedia_vid_port_get_passive_port(pjmedia_vid_port *vid_port) nogil
int pjmedia_vid_port_disconnect(pjmedia_vid_port *vid_port) nogil
void pjmedia_vid_port_destroy(pjmedia_vid_port *vid_port) nogil
pjmedia_vid_dev_stream *pjmedia_vid_port_get_stream(pjmedia_vid_port *vid_port) nogil
# video tee
int pjmedia_vid_tee_create(pj_pool_t *pool, pjmedia_format_ptr_const fmt, unsigned int max_dst_cnt, pjmedia_port **p_vid_tee) nogil
int pjmedia_vid_tee_add_dst_port2(pjmedia_port *vid_tee, unsigned int option, pjmedia_port *port) nogil
int pjmedia_vid_tee_remove_dst_port(pjmedia_port *vid_tee, pjmedia_port *port) nogil
# sdp
enum:
PJMEDIA_MAX_SDP_FMT
enum:
PJMEDIA_MAX_SDP_ATTR
enum:
PJMEDIA_MAX_SDP_MEDIA
enum:
PJMEDIA_MAX_SDP_BANDW
struct pjmedia_sdp_attr:
pj_str_t name
pj_str_t value
struct pjmedia_sdp_bandw:
pj_str_t modifier
unsigned int value
struct pjmedia_sdp_conn:
pj_str_t net_type
pj_str_t addr_type
pj_str_t addr
struct pjmedia_sdp_media_desc:
pj_str_t media
unsigned int port
unsigned int port_count
pj_str_t transport
unsigned int fmt_count
pj_str_t fmt[PJMEDIA_MAX_SDP_FMT]
struct pjmedia_sdp_media:
pjmedia_sdp_media_desc desc
pjmedia_sdp_conn *conn
unsigned int attr_count
pjmedia_sdp_attr *attr[PJMEDIA_MAX_SDP_ATTR]
unsigned int bandw_count
pjmedia_sdp_bandw *bandw[PJMEDIA_MAX_SDP_BANDW]
struct pjmedia_sdp_session_origin:
pj_str_t user
unsigned int id
unsigned int version
pj_str_t net_type
pj_str_t addr_type
pj_str_t addr
struct pjmedia_sdp_session_time:
unsigned int start
unsigned int stop
struct pjmedia_sdp_session:
pjmedia_sdp_session_origin origin
pj_str_t name
pjmedia_sdp_conn *conn
pjmedia_sdp_session_time time
unsigned int attr_count
pjmedia_sdp_attr *attr[PJMEDIA_MAX_SDP_ATTR]
unsigned int bandw_count
pjmedia_sdp_bandw *bandw[PJMEDIA_MAX_SDP_BANDW]
unsigned int media_count
pjmedia_sdp_media *media[PJMEDIA_MAX_SDP_MEDIA]
ctypedef pjmedia_sdp_session *pjmedia_sdp_session_ptr_const "const pjmedia_sdp_session *"
pjmedia_sdp_media *pjmedia_sdp_media_clone(pj_pool_t *pool, pjmedia_sdp_media *rhs) nogil
pjmedia_sdp_session *pjmedia_sdp_session_clone(pj_pool_t *pool, pjmedia_sdp_session_ptr_const sdp) nogil
int pjmedia_sdp_print(pjmedia_sdp_session_ptr_const sdp, char *buf, int length)
int pjmedia_sdp_parse(pj_pool_t *pool, char *buf, int length, pjmedia_sdp_session **p_sdp) nogil
# sdp negotiation
enum pjmedia_sdp_neg_state:
PJMEDIA_SDP_NEG_STATE_NULL
PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER
PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER
PJMEDIA_SDP_NEG_STATE_WAIT_NEGO
PJMEDIA_SDP_NEG_STATE_DONE
struct pjmedia_sdp_neg
int pjmedia_sdp_neg_create_w_local_offer(pj_pool_t *pool, pjmedia_sdp_session_ptr_const local, pjmedia_sdp_neg **neg) nogil
int pjmedia_sdp_neg_create_w_remote_offer(pj_pool_t *pool, pjmedia_sdp_session_ptr_const initial, pjmedia_sdp_session_ptr_const remote, pjmedia_sdp_neg **neg) nogil
int pjmedia_sdp_neg_set_local_answer(pj_pool_t *pool, pjmedia_sdp_neg *neg, pjmedia_sdp_session_ptr_const local) nogil
int pjmedia_sdp_neg_set_remote_answer(pj_pool_t *pool, pjmedia_sdp_neg *neg, pjmedia_sdp_session_ptr_const remote) nogil
int pjmedia_sdp_neg_set_remote_offer(pj_pool_t *pool, pjmedia_sdp_neg *neg, pjmedia_sdp_session_ptr_const remote) nogil
int pjmedia_sdp_neg_get_neg_remote(pjmedia_sdp_neg *neg, pjmedia_sdp_session_ptr_const *remote) nogil
int pjmedia_sdp_neg_get_neg_local(pjmedia_sdp_neg *neg, pjmedia_sdp_session_ptr_const *local) nogil
int pjmedia_sdp_neg_get_active_remote(pjmedia_sdp_neg *neg, pjmedia_sdp_session_ptr_const *remote) nogil
int pjmedia_sdp_neg_get_active_local(pjmedia_sdp_neg *neg, pjmedia_sdp_session_ptr_const *local) nogil
int pjmedia_sdp_neg_modify_local_offer (pj_pool_t *pool, pjmedia_sdp_neg *neg, pjmedia_sdp_session_ptr_const local) nogil
int pjmedia_sdp_neg_cancel_offer(pjmedia_sdp_neg *neg) nogil
int pjmedia_sdp_neg_negotiate(pj_pool_t *poll, pjmedia_sdp_neg *neg, int allow_asym) nogil
pjmedia_sdp_neg_state pjmedia_sdp_neg_get_state(pjmedia_sdp_neg *neg) nogil
char *pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_state state) nogil
# transport
enum pjmedia_transport_type:
PJMEDIA_TRANSPORT_TYPE_ICE
PJMEDIA_TRANSPORT_TYPE_SRTP
PJMEDIA_TRANSPORT_TYPE_ZRTP
struct pjmedia_sock_info:
pj_sockaddr rtp_addr_name
ctypedef pjmedia_sock_info *pjmedia_sock_info_ptr_const "const pjmedia_sock_info *"
struct pjmedia_transport:
char *name
pjmedia_transport_type type
void *user_data
struct pjmedia_transport_specific_info:
pjmedia_transport_type type
char *buffer
struct pjmedia_transport_info:
pjmedia_sock_info sock_info
pj_sockaddr src_rtp_name
int specific_info_cnt
pjmedia_transport_specific_info *spc_info
void pjmedia_transport_info_init(pjmedia_transport_info *info) nogil
int pjmedia_transport_udp_create3(pjmedia_endpt *endpt, int af, char *name, pj_str_t *addr, int port,
unsigned int options, pjmedia_transport **p_tp) nogil
int pjmedia_transport_get_info(pjmedia_transport *tp, pjmedia_transport_info *info) nogil
void *pjmedia_transport_info_get_spc_info(pjmedia_transport_info *info, pjmedia_transport_type type)
int pjmedia_transport_close(pjmedia_transport *tp) nogil
int pjmedia_transport_media_create(pjmedia_transport *tp, pj_pool_t *sdp_pool, unsigned int options,
pjmedia_sdp_session *rem_sdp, unsigned int media_index) nogil
int pjmedia_transport_encode_sdp(pjmedia_transport *tp, pj_pool_t *sdp_pool, pjmedia_sdp_session *sdp,
pjmedia_sdp_session *rem_sdp, unsigned int media_index) nogil
int pjmedia_transport_media_start(pjmedia_transport *tp, pj_pool_t *tmp_pool, pjmedia_sdp_session *sdp_local,
pjmedia_sdp_session *sdp_remote, unsigned int media_index) nogil
int pjmedia_transport_media_stop(pjmedia_transport *tp) nogil
int pjmedia_endpt_create_sdp(pjmedia_endpt *endpt, pj_pool_t *pool, unsigned int stream_cnt,
pjmedia_sock_info *sock_info, pjmedia_sdp_session **p_sdp) nogil
int pjmedia_endpt_create_base_sdp(pjmedia_endpt *endpt, pj_pool_t *pool, pj_str_ptr_const sess_name,
pj_sockaddr_ptr_const origin, pjmedia_sdp_session **p_sdp) nogil
int pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt, pj_pool_t *pool, pjmedia_sock_info_ptr_const si,
unsigned int options, pjmedia_sdp_media **p_media) nogil
int pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt, pj_pool_t *pool, pjmedia_sock_info_ptr_const si,
unsigned int options, pjmedia_sdp_media **p_media) nogil
# SRTP
struct pjmedia_srtp_crypto:
pj_str_t key
pj_str_t name
unsigned int flags
struct pjmedia_srtp_info:
int active
pjmedia_srtp_crypto tx_policy
enum pjmedia_srtp_use:
PJMEDIA_SRTP_MANDATORY
struct pjmedia_srtp_setting:
pjmedia_srtp_use use
void pjmedia_srtp_setting_default(pjmedia_srtp_setting *opt) nogil
int pjmedia_transport_srtp_create(pjmedia_endpt *endpt, pjmedia_transport *tp,
pjmedia_srtp_setting *opt, pjmedia_transport **p_tp) nogil
# ZRTP
struct pjmedia_zrtp_info:
int active
char cipher[128]
struct pjmedia_zrtp_cb:
void secure_on(pjmedia_transport *tp, char* cipher) with gil
void secure_off(pjmedia_transport *tp) with gil
void show_sas(pjmedia_transport *tp, char* sas, int verified) with gil
void confirm_go_clear(pjmedia_transport *tp) with gil
void show_message(pjmedia_transport *tp, int severity, int subCode) with gil
void negotiation_failed(pjmedia_transport *tp, int severity, int subCode) with gil
void not_supported_by_other(pjmedia_transport *tp) with gil
void ask_enrollment(pjmedia_transport *tp, int info) with gil
void inform_enrollment(pjmedia_transport *tp, int info) with gil
void sign_sas(pjmedia_transport *tp, unsigned char* sas) with gil
int check_sas_signature(pjmedia_transport *tp, unsigned char* sas) with gil
int pjmedia_transport_zrtp_create(pjmedia_endpt *endpt, pj_timer_heap_t *timer_heap, pjmedia_transport *tp,
pjmedia_transport **p_tp, int close_slave) nogil
int pjmedia_transport_zrtp_initialize(pjmedia_transport *tp, char_ptr_const zidFilename,
int autoEnable, pjmedia_zrtp_cb *zrtp_cb) nogil
void pjmedia_transport_zrtp_setSASVerified(pjmedia_transport *tp, int verified) nogil
char* pjmedia_transport_zrtp_getPeerName(pjmedia_transport *tp) nogil
void pjmedia_transport_zrtp_putPeerName(pjmedia_transport *tp, const char *name) nogil
int pjmedia_transport_zrtp_getPeerZid(pjmedia_transport *tp, unsigned char* data) nogil
void pjmedia_transport_zrtp_setEnableZrtp(pjmedia_transport *tp, int onOff) nogil
char* pjmedia_transport_zrtp_getMultiStreamParameters(pjmedia_transport *tp, int *length) nogil
void pjmedia_transport_zrtp_setMultiStreamParameters(pjmedia_transport *tp, const char *parameters, int length, pjmedia_transport *master_tp) nogil
# ICE
struct pjmedia_ice_cb:
void on_ice_complete(pjmedia_transport *tp, pj_ice_strans_op op, int status) with gil
void on_ice_state(pjmedia_transport *tp, pj_ice_strans_state prev, pj_ice_strans_state curr) with gil
void on_ice_stop(pjmedia_transport *tp, char *reason, int err) with gil
int pjmedia_ice_create2(pjmedia_endpt *endpt, char *name, unsigned int comp_cnt, pj_ice_strans_cfg *cfg,
pjmedia_ice_cb *cb, unsigned int options, pjmedia_transport **p_tp) nogil
pj_ice_strans *pjmedia_ice_get_strans(pjmedia_transport *tp) with gil
# stream
struct pjmedia_codec_param_setting:
unsigned int vad
struct pjmedia_codec_param:
pjmedia_codec_param_setting setting
struct pjmedia_stream_info:
pjmedia_codec_info fmt
pjmedia_codec_param *param
unsigned int tx_event_pt
int use_ka
struct pjmedia_rtcp_stream_stat_loss_type:
unsigned int burst
unsigned int random
struct pjmedia_rtcp_stream_stat:
unsigned int pkt
unsigned int bytes
unsigned int discard
unsigned int loss
unsigned int reorder
unsigned int dup
pj_math_stat loss_period
pjmedia_rtcp_stream_stat_loss_type loss_type
pj_math_stat jitter
struct pjmedia_rtcp_stat:
pjmedia_rtcp_stream_stat tx
pjmedia_rtcp_stream_stat rx
pj_math_stat rtt
struct pjmedia_stream
int pjmedia_stream_info_from_sdp(pjmedia_stream_info *si, pj_pool_t *pool, pjmedia_endpt *endpt,
pjmedia_sdp_session *local, pjmedia_sdp_session *remote, unsigned int stream_idx) nogil
int pjmedia_stream_create(pjmedia_endpt *endpt, pj_pool_t *pool, pjmedia_stream_info *info,
pjmedia_transport *tp, void *user_data, pjmedia_stream **p_stream) nogil
int pjmedia_stream_destroy(pjmedia_stream *stream) nogil
int pjmedia_stream_get_port(pjmedia_stream *stream, pjmedia_port **p_port) nogil
int pjmedia_stream_start(pjmedia_stream *stream) nogil
int pjmedia_stream_dial_dtmf(pjmedia_stream *stream, pj_str_t *ascii_digit) nogil
int pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream,
void cb(pjmedia_stream *stream, void *user_data, int digit) with gil,
void *user_data) nogil
int pjmedia_stream_pause(pjmedia_stream *stream, pjmedia_dir dir) nogil
int pjmedia_stream_resume(pjmedia_stream *stream, pjmedia_dir dir) nogil
int pjmedia_stream_get_stat(pjmedia_stream *stream, pjmedia_rtcp_stat *stat) nogil
# wav player
enum:
PJMEDIA_FILE_NO_LOOP
int pjmedia_port_destroy(pjmedia_port *port) nogil
int pjmedia_wav_player_port_create(pj_pool_t *pool, char *filename, unsigned int ptime, unsigned int flags,
unsigned int buff_size, pjmedia_port **p_port) nogil
int pjmedia_wav_player_set_eof_cb(pjmedia_port *port, void *user_data,
int cb(pjmedia_port *port, void *usr_data) with gil) nogil
int pjmedia_wav_player_port_set_pos(pjmedia_port *port, unsigned int offset) nogil
# wav recorder
enum pjmedia_file_writer_option:
PJMEDIA_FILE_WRITE_PCM
int pjmedia_wav_writer_port_create(pj_pool_t *pool, char *filename, unsigned int clock_rate,
unsigned int channel_count, unsigned int samples_per_frame,
unsigned int bits_per_sample, unsigned int flags, int buff_size,
pjmedia_port **p_port) nogil
# tone generator
enum:
PJMEDIA_TONEGEN_MAX_DIGITS
struct pjmedia_tone_desc:
short freq1
short freq2
short on_msec
short off_msec
short volume
short flags
struct pjmedia_tone_digit:
char digit
short on_msec
short off_msec
short volume
int pjmedia_tonegen_create(pj_pool_t *pool, unsigned int clock_rate, unsigned int channel_count,
unsigned int samples_per_frame, unsigned int bits_per_sample,
unsigned int options, pjmedia_port **p_port) nogil
int pjmedia_tonegen_play(pjmedia_port *tonegen, unsigned int count, pjmedia_tone_desc *tones, unsigned int options) nogil
int pjmedia_tonegen_play_digits(pjmedia_port *tonegen, unsigned int count,
pjmedia_tone_digit *digits, unsigned int options) nogil
int pjmedia_tonegen_stop(pjmedia_port *tonegen) nogil
int pjmedia_tonegen_is_busy(pjmedia_port *tonegen) nogil
cdef extern from "pjmedia_videodev.h":
ctypedef void (*pjmedia_vid_dev_fb_frame_cb)(pjmedia_frame_ptr_const frame, pjmedia_rect_size size, void *user_data)
int pjmedia_vid_dev_fb_set_callback(pjmedia_vid_dev_stream *strm, pjmedia_vid_dev_fb_frame_cb cb, void *user_data)
cdef extern from "pjmedia-codec.h":
# codecs
enum:
PJMEDIA_SPEEX_NO_NB
struct speex_options:
unsigned int option
int quality
int complexity
struct ilbc_options:
unsigned mode
struct pjmedia_audio_codec_config:
speex_options speex
ilbc_options ilbc
void pjmedia_audio_codec_config_default(pjmedia_audio_codec_config *cfg)
int pjmedia_codec_register_audio_codecs(pjmedia_endpt *endpt, const pjmedia_audio_codec_config *c) nogil
int pjmedia_codec_ffmpeg_vid_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf) nogil
int pjmedia_codec_ffmpeg_vid_deinit() nogil
int pjmedia_codec_vpx_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf) nogil
int pjmedia_codec_vpx_deinit() nogil
cdef extern from "pjsip.h":
# messages
enum pjsip_status_code:
PJSIP_SC_TSX_TIMEOUT
PJSIP_SC_TSX_TRANSPORT_ERROR
PJSIP_TLS_EUNKNOWN
PJSIP_TLS_EINVMETHOD
PJSIP_TLS_ECACERT
PJSIP_TLS_ECERTFILE
PJSIP_TLS_EKEYFILE
PJSIP_TLS_ECIPHER
PJSIP_TLS_ECTX
enum pjsip_uri_context_e:
PJSIP_URI_IN_CONTACT_HDR
struct pjsip_param:
pj_str_t name
pj_str_t value
struct pjsip_uri
struct pjsip_sip_uri:
pj_str_t user
pj_str_t passwd
pj_str_t host
int port
pj_str_t user_param
pj_str_t method_param
pj_str_t transport_param
int ttl_param
int lr_param
pj_str_t maddr_param
pjsip_param other_param
pjsip_param header_param
struct pjsip_name_addr:
pj_str_t display
pjsip_uri *uri
struct pjsip_media_type:
pj_str_t type
pj_str_t subtype
pjsip_param param
enum pjsip_method_e:
PJSIP_OPTIONS_METHOD
PJSIP_CANCEL_METHOD
PJSIP_OTHER_METHOD
struct pjsip_method:
pjsip_method_e id
pj_str_t name
struct pjsip_host_port:
pj_str_t host
int port
enum pjsip_hdr_e:
PJSIP_H_VIA
PJSIP_H_CALL_ID
PJSIP_H_CONTACT
PJSIP_H_CSEQ
PJSIP_H_EXPIRES
PJSIP_H_FROM
struct pjsip_hdr:
pjsip_hdr_e type
pj_str_t name
ctypedef pjsip_hdr *pjsip_hdr_ptr_const "const pjsip_hdr*"
struct pjsip_generic_array_hdr:
unsigned int count
pj_str_t *values
struct pjsip_generic_string_hdr:
pj_str_t name
pj_str_t hvalue
struct pjsip_cid_hdr:
pj_str_t id
struct pjsip_contact_hdr:
int star
pjsip_uri *uri
int q1000
int expires
pjsip_param other_param
struct pjsip_clen_hdr:
int len
struct pjsip_ctype_hdr:
pjsip_media_type media
struct pjsip_cseq_hdr:
int cseq
pjsip_method method
struct pjsip_generic_int_hdr:
int ivalue
ctypedef pjsip_generic_int_hdr pjsip_expires_hdr
struct pjsip_fromto_hdr:
pjsip_uri *uri
pj_str_t tag
pjsip_param other_param
struct pjsip_routing_hdr:
pjsip_name_addr name_addr
pjsip_param other_param
ctypedef pjsip_routing_hdr pjsip_route_hdr
struct pjsip_retry_after_hdr:
int ivalue
pjsip_param param
pj_str_t comment
struct pjsip_via_hdr:
pj_str_t transport
pjsip_host_port sent_by
int ttl_param
int rport_param
pj_str_t maddr_param
pj_str_t recvd_param
pj_str_t branch_param
pjsip_param other_param
pj_str_t comment
enum:
PJSIP_MAX_ACCEPT_COUNT
struct pjsip_msg_body:
pjsip_media_type content_type
void *data
unsigned int len
struct pjsip_request_line:
pjsip_method method
pjsip_uri *uri
struct pjsip_status_line:
int code
pj_str_t reason
union pjsip_msg_line:
pjsip_request_line req
pjsip_status_line status
enum pjsip_msg_type_e:
PJSIP_REQUEST_MSG
PJSIP_RESPONSE_MSG
struct pjsip_msg:
pjsip_msg_type_e type
pjsip_msg_line line
pjsip_hdr hdr
pjsip_msg_body *body
struct pjsip_buffer:
char *start
char *cur
struct pjsip_tx_data_tp_info:
char *dst_name
int dst_port
pjsip_transport *transport
struct pjsip_tx_data:
pjsip_msg *msg
pj_pool_t *pool
pjsip_buffer buf
pjsip_tx_data_tp_info tp_info
struct pjsip_rx_data_tp_info:
pj_pool_t *pool
pjsip_transport *transport
struct pjsip_rx_data_pkt_info:
pj_time_val timestamp
char *packet
int len
char *src_name
int src_port
struct pjsip_rx_data_msg_info:
pjsip_msg *msg
pjsip_fromto_hdr *from_hdr "from"
pjsip_fromto_hdr *to_hdr "to"
pjsip_via_hdr *via
struct pjsip_rx_data:
pjsip_rx_data_pkt_info pkt_info
pjsip_rx_data_tp_info tp_info
pjsip_rx_data_msg_info msg_info
void *pjsip_hdr_clone(pj_pool_t *pool, void *hdr) nogil
void pjsip_msg_add_hdr(pjsip_msg *msg, pjsip_hdr *hdr) nogil
void *pjsip_msg_find_hdr(pjsip_msg *msg, pjsip_hdr_e type, void *start) nogil
void *pjsip_msg_find_hdr_by_name(pjsip_msg *msg, pj_str_t *name, void *start) nogil
void *pjsip_msg_find_remove_hdr_by_name(pjsip_msg *msg, pj_str_t *name, void *start) nogil
pjsip_generic_string_hdr *pjsip_generic_string_hdr_create(pj_pool_t *pool, pj_str_t *hname, pj_str_t *hvalue) nogil
pjsip_contact_hdr *pjsip_contact_hdr_create(pj_pool_t *pool) nogil
pjsip_expires_hdr *pjsip_expires_hdr_create(pj_pool_t *pool, int value) nogil
pjsip_msg_body *pjsip_msg_body_create(pj_pool_t *pool, pj_str_t *type, pj_str_t *subtype, pj_str_t *text) nogil
pjsip_msg_body *pjsip_msg_body_clone(pj_pool_t *pool, const pjsip_msg_body *body) nogil
pjsip_route_hdr *pjsip_route_hdr_init(pj_pool_t *pool, void *mem) nogil
void pjsip_sip_uri_init(pjsip_sip_uri *url, int secure) nogil
int pjsip_tx_data_dec_ref(pjsip_tx_data *tdata) nogil
void pjsip_tx_data_add_ref(pjsip_tx_data *tdata) nogil
pj_str_t *pjsip_uri_get_scheme(pjsip_uri *uri) nogil
void *pjsip_uri_get_uri(pjsip_uri *uri) nogil
int pjsip_uri_print(pjsip_uri_context_e context, void *uri, char *buf, unsigned int size) nogil
int PJSIP_URI_SCHEME_IS_SIP(pjsip_sip_uri *uri) nogil
enum:
PJSIP_PARSE_URI_AS_NAMEADDR
pjsip_uri *pjsip_parse_uri(pj_pool_t *pool, char *buf, unsigned int size, unsigned int options) nogil
void pjsip_method_init_np(pjsip_method *m, pj_str_t *str) nogil
pj_str_t *pjsip_get_status_text(int status_code) nogil
int pjsip_print_body(pjsip_msg_body *msg_body, char **buf, int *len)
# module
enum pjsip_module_priority:
PJSIP_MOD_PRIORITY_APPLICATION
PJSIP_MOD_PRIORITY_DIALOG_USAGE
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER
struct pjsip_event
struct pjsip_transaction
struct pjsip_module:
pj_str_t name
int id
int priority
int on_rx_request(pjsip_rx_data *rdata) with gil
int on_rx_response(pjsip_rx_data *rdata) with gil
int on_tx_request(pjsip_tx_data *tdata) with gil
int on_tx_response(pjsip_tx_data *tdata) with gil
void on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) with gil
# endpoint
struct pjsip_endpoint
int pjsip_endpt_create(pj_pool_factory *pf, char *name, pjsip_endpoint **endpt) nogil
void pjsip_endpt_destroy(pjsip_endpoint *endpt) nogil
pj_pool_t *pjsip_endpt_create_pool(pjsip_endpoint *endpt, char *pool_name, int initial, int increment) nogil
void pjsip_endpt_release_pool(pjsip_endpoint *endpt, pj_pool_t *pool) nogil
int pjsip_endpt_handle_events(pjsip_endpoint *endpt, pj_time_val *max_timeout) nogil
int pjsip_endpt_register_module(pjsip_endpoint *endpt, pjsip_module *module) nogil
int pjsip_endpt_schedule_timer(pjsip_endpoint *endpt, pj_timer_entry *entry, pj_time_val *delay) nogil
void pjsip_endpt_cancel_timer(pjsip_endpoint *endpt, pj_timer_entry *entry) nogil
enum:
PJSIP_H_ACCEPT
PJSIP_H_ALLOW
PJSIP_H_SUPPORTED
pjsip_hdr_ptr_const pjsip_endpt_get_capability(pjsip_endpoint *endpt, int htype, pj_str_t *hname) nogil
int pjsip_endpt_add_capability(pjsip_endpoint *endpt, pjsip_module *mod, int htype,
pj_str_t *hname, unsigned count, pj_str_t *tags) nogil
int pjsip_endpt_create_response(pjsip_endpoint *endpt, pjsip_rx_data *rdata,
int st_code, pj_str_t *st_text, pjsip_tx_data **p_tdata) nogil
int pjsip_endpt_send_response2(pjsip_endpoint *endpt, pjsip_rx_data *rdata,
pjsip_tx_data *tdata, void *token, void *cb) nogil
int pjsip_endpt_respond_stateless(pjsip_endpoint *endpt, pjsip_rx_data *rdata,
int st_code, pj_str_t *st_text, pjsip_hdr *hdr_list, pjsip_msg_body *body) nogil
int pjsip_endpt_create_request(pjsip_endpoint *endpt, pjsip_method *method, pj_str_t *target, pj_str_t *frm,
pj_str_t *to, pj_str_t *contact, pj_str_t *call_id,
int cseq,pj_str_t *text, pjsip_tx_data **p_tdata) nogil
pj_timer_heap_t *pjsip_endpt_get_timer_heap(pjsip_endpoint *endpt) nogil
int pjsip_endpt_create_resolver(pjsip_endpoint *endpt, pj_dns_resolver **p_resv) nogil
int pjsip_endpt_set_resolver(pjsip_endpoint *endpt, pj_dns_resolver *resv) nogil
pj_dns_resolver* pjsip_endpt_get_resolver(pjsip_endpoint *endpt) nogil
# transports
enum pjsip_ssl_method:
PJSIP_TLSV1_METHOD
PJSIP_SSLV23_METHOD
struct pjsip_transport:
char *type_name
pj_sockaddr local_addr
pjsip_host_port local_name
pjsip_host_port remote_name
struct pjsip_tpfactory:
pjsip_host_port addr_name
int destroy(pjsip_tpfactory *factory) nogil
struct pjsip_tls_setting:
pj_str_t ca_list_file
pj_str_t cert_file
pj_str_t privkey_file
int method
int verify_server
pj_time_val timeout
enum pjsip_tpselector_type:
PJSIP_TPSELECTOR_TRANSPORT
union pjsip_tpselector_u:
pjsip_transport *transport
struct pjsip_tpselector:
pjsip_tpselector_type type
pjsip_tpselector_u u
int pjsip_transport_shutdown(pjsip_transport *tp) nogil
int pjsip_udp_transport_start(pjsip_endpoint *endpt, pj_sockaddr_in *local, pjsip_host_port *a_name,
unsigned int async_cnt, pjsip_transport **p_transport) nogil
int pjsip_tcp_transport_start2(pjsip_endpoint *endpt, pj_sockaddr_in *local, pjsip_host_port *a_name,
unsigned int async_cnt, pjsip_tpfactory **p_tpfactory) nogil
int pjsip_tls_transport_start(pjsip_endpoint *endpt, pjsip_tls_setting *opt, pj_sockaddr_in *local,
pjsip_host_port *a_name, unsigned async_cnt, pjsip_tpfactory **p_factory) nogil
void pjsip_tls_setting_default(pjsip_tls_setting *tls_opt) nogil
int pjsip_transport_shutdown(pjsip_transport *tp) nogil
# transaction layer
enum pjsip_role_e:
PJSIP_ROLE_UAC
PJSIP_ROLE_UAS
enum pjsip_tsx_state_e:
PJSIP_TSX_STATE_TRYING
PJSIP_TSX_STATE_PROCEEDING
PJSIP_TSX_STATE_COMPLETED
PJSIP_TSX_STATE_TERMINATED
struct pjsip_transaction:
int status_code
pj_str_t status_text
pjsip_role_e role
pjsip_tx_data *last_tx
pjsip_tsx_state_e state
void **mod_data
pjsip_method method
int pjsip_tsx_layer_init_module(pjsip_endpoint *endpt) nogil
int pjsip_tsx_create_key(pj_pool_t *pool, pj_str_t *key, pjsip_role_e role,
pjsip_method *method, pjsip_rx_data *rdata) nogil
pjsip_transaction *pjsip_tsx_layer_find_tsx(pj_str_t *key, int lock) nogil
int pjsip_tsx_create_uac(pjsip_module *tsx_user, pjsip_tx_data *tdata, pjsip_transaction **p_tsx) nogil
int pjsip_tsx_terminate(pjsip_transaction *tsx, int code) nogil
int pjsip_tsx_send_msg(pjsip_transaction *tsx, pjsip_tx_data *tdata) nogil
pjsip_transaction *pjsip_rdata_get_tsx(pjsip_rx_data *rdata) nogil
int pjsip_tsx_create_uas(pjsip_module *tsx_user, pjsip_rx_data *rdata, pjsip_transaction **p_tsx) nogil
void pjsip_tsx_recv_msg(pjsip_transaction *tsx, pjsip_rx_data *rdata) nogil
# event
enum pjsip_event_id_e:
PJSIP_EVENT_TSX_STATE
PJSIP_EVENT_RX_MSG
PJSIP_EVENT_TX_MSG
PJSIP_EVENT_TRANSPORT_ERROR
PJSIP_EVENT_TIMER
union pjsip_event_body_tsx_state_src:
pjsip_rx_data *rdata
pjsip_tx_data *tdata
struct pjsip_event_body_tsx_state:
pjsip_event_body_tsx_state_src src
pjsip_transaction *tsx
pjsip_event_id_e type
struct pjsip_event_body_rx_msg:
pjsip_rx_data *rdata
union pjsip_event_body:
pjsip_event_body_tsx_state tsx_state
pjsip_event_body_rx_msg rx_msg
struct pjsip_event:
pjsip_event_id_e type
pjsip_event_body body
int pjsip_endpt_send_request(pjsip_endpoint *endpt, pjsip_tx_data *tdata, int timeout,
void *token, void cb(void *token, pjsip_event *e) with gil) nogil
# auth
enum:
PJSIP_EFAILEDCREDENTIAL
enum pjsip_cred_data_type:
PJSIP_CRED_DATA_PLAIN_PASSWD
PJSIP_CRED_DATA_DIGEST
struct pjsip_cred_info:
pj_str_t realm
pj_str_t scheme
pj_str_t username
pjsip_cred_data_type data_type
pj_str_t data
struct pjsip_auth_clt_sess:
pass
int pjsip_auth_clt_init(pjsip_auth_clt_sess *sess, pjsip_endpoint *endpt, pj_pool_t *pool, unsigned int options) nogil
int pjsip_auth_clt_set_credentials(pjsip_auth_clt_sess *sess, int cred_cnt, pjsip_cred_info *c) nogil
int pjsip_auth_clt_reinit_req(pjsip_auth_clt_sess *sess, pjsip_rx_data *rdata,
pjsip_tx_data *old_request, pjsip_tx_data **new_request) nogil
# dialog layer
ctypedef pjsip_module pjsip_user_agent
struct pjsip_dlg_party:
pjsip_contact_hdr *contact
pjsip_fromto_hdr *info
struct pjsip_dialog:
pjsip_auth_clt_sess auth_sess
pjsip_cid_hdr *call_id
pj_pool_t *pool
pjsip_dlg_party local
pjsip_dlg_party remote
struct pjsip_ua_init_param:
pjsip_dialog *on_dlg_forked(pjsip_dialog *first_set, pjsip_rx_data *res) nogil
int pjsip_ua_init_module(pjsip_endpoint *endpt, pjsip_ua_init_param *prm) nogil
pjsip_user_agent *pjsip_ua_instance() nogil
int pjsip_dlg_create_uac(pjsip_user_agent *ua, pj_str_t *local_uri, pj_str_t *local_contact,
pj_str_t *remote_uri, pj_str_t *target, pjsip_dialog **p_dlg) nogil
int pjsip_dlg_set_route_set(pjsip_dialog *dlg, pjsip_route_hdr *route_set) nogil
int pjsip_dlg_create_uas_and_inc_lock(pjsip_user_agent *ua, pjsip_rx_data *rdata, pj_str_t *contact, pjsip_dialog **p_dlg) nogil
int pjsip_dlg_terminate(pjsip_dialog *dlg) nogil
int pjsip_dlg_set_transport(pjsip_dialog *dlg, pjsip_tpselector *sel) nogil
int pjsip_dlg_respond(pjsip_dialog *dlg, pjsip_rx_data *rdata, int st_code,
pj_str_t *st_text, pjsip_hdr *hdr_list, pjsip_msg_body *body) nogil
int pjsip_dlg_create_response(pjsip_dialog *dlg, pjsip_rx_data *rdata,
int st_code, pj_str_t *st_text, pjsip_tx_data **tdata) nogil
int pjsip_dlg_modify_response(pjsip_dialog *dlg, pjsip_tx_data *tdata, int st_code, pj_str_t *st_text) nogil
int pjsip_dlg_send_response(pjsip_dialog *dlg, pjsip_transaction *tsx, pjsip_tx_data *tdata) nogil
void pjsip_dlg_inc_lock(pjsip_dialog *dlg) nogil
void pjsip_dlg_dec_lock(pjsip_dialog *dlg) nogil
int pjsip_dlg_inc_session(pjsip_dialog *dlg, pjsip_module *mod) nogil
int pjsip_dlg_dec_session(pjsip_dialog *dlg, pjsip_module *mod) nogil
cdef extern from "pjsip-simple/evsub_msg.h":
struct pjsip_event_hdr:
pj_str_t event_type
pj_str_t id_param
pjsip_param other_param
struct pjsip_sub_state_hdr:
pj_str_t sub_state
pj_str_t reason_param
int expires_param
int retry_after
pjsip_param other_param
pjsip_event_hdr *pjsip_event_hdr_create(pj_pool_t *pool) nogil
cdef extern from "pjsip_simple.h":
# subscribe / notify
enum:
PJSIP_EVSUB_NO_EVENT_ID
enum pjsip_evsub_state:
PJSIP_EVSUB_STATE_PENDING
PJSIP_EVSUB_STATE_ACTIVE
PJSIP_EVSUB_STATE_TERMINATED
struct pjsip_evsub
struct pjsip_evsub_user:
void on_evsub_state(pjsip_evsub *sub, pjsip_event *event) with gil
void on_tsx_state(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) with gil
void on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text,
pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil
void on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
pj_str_t **p_st_text,pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil
void on_client_refresh(pjsip_evsub *sub) with gil
void on_server_timeout(pjsip_evsub *sub) with gil
int pjsip_evsub_init_module(pjsip_endpoint *endpt) nogil
int pjsip_evsub_register_pkg(pjsip_module *pkg_mod, pj_str_t *event_name,
unsigned int expires, unsigned int accept_cnt, pj_str_t *accept) nogil
int pjsip_evsub_create_uac(pjsip_dialog *dlg, pjsip_evsub_user *user_cb,
pj_str_t *event, int option, pjsip_evsub **p_evsub) nogil
int pjsip_evsub_create_uas(pjsip_dialog *dlg, pjsip_evsub_user *user_cb,
pjsip_rx_data *rdata, unsigned int option, pjsip_evsub **p_evsub) nogil
int pjsip_evsub_initiate(pjsip_evsub *sub, void *method, unsigned int expires, pjsip_tx_data **p_tdata) nogil
int pjsip_evsub_send_request(pjsip_evsub *sub, pjsip_tx_data *tdata) nogil
int pjsip_evsub_terminate(pjsip_evsub *sub, int notify) nogil
char *pjsip_evsub_get_state_name(pjsip_evsub *sub) nogil
void pjsip_evsub_set_mod_data(pjsip_evsub *sub, int mod_id, void *data) nogil
void *pjsip_evsub_get_mod_data(pjsip_evsub *sub, int mod_id) nogil
void pjsip_evsub_update_expires(pjsip_evsub *sub, int interval) nogil
void pjsip_evsub_set_timer(pjsip_evsub *sub, int timer_id, int seconds) nogil
pjsip_hdr *pjsip_evsub_get_allow_events_hdr(pjsip_module *m) nogil
int pjsip_evsub_notify(pjsip_evsub *sub, pjsip_evsub_state state,
pj_str_t *state_str, pj_str_t *reason, pjsip_tx_data **p_tdata) nogil
cdef extern from "pjsip_ua.h":
# 100rel / PRACK
int pjsip_100rel_init_module(pjsip_endpoint *endpt) nogil
# invite sessions
enum pjsip_inv_option:
PJSIP_INV_SUPPORT_100REL
enum pjsip_inv_state:
PJSIP_INV_STATE_INCOMING
PJSIP_INV_STATE_CONFIRMED
enum pjmedia_mod_offer_flag:
PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE
struct pjsip_inv_session:
pjsip_inv_state state
void **mod_data
pjmedia_sdp_neg *neg
unsigned sdp_neg_flags
int cause
pj_str_t cause_text
int cancelling
pjsip_transaction *invite_tsx
struct pjsip_inv_callback:
void on_state_changed(pjsip_inv_session *inv, pjsip_event *e) with gil
void on_new_session(pjsip_inv_session *inv, pjsip_event *e) with gil
void on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) with gil
void on_media_update(pjsip_inv_session *inv, int status) with gil
int on_rx_reinvite(pjsip_inv_session *inv, pjmedia_sdp_session_ptr_const offer, pjsip_rx_data *rdata) with gil
int pjsip_inv_usage_init(pjsip_endpoint *endpt, pjsip_inv_callback *cb) nogil
int pjsip_inv_terminate(pjsip_inv_session *inv, int st_code, int notify) nogil
int pjsip_inv_end_session(pjsip_inv_session *inv, int st_code, pj_str_t *st_text, pjsip_tx_data **p_tdata) nogil
int pjsip_inv_cancel_reinvite(pjsip_inv_session *inv, pjsip_tx_data **p_tdata) nogil
int pjsip_inv_send_msg(pjsip_inv_session *inv, pjsip_tx_data *tdata) nogil
int pjsip_inv_verify_request(pjsip_rx_data *rdata, unsigned int *options, pjmedia_sdp_session *sdp,
pjsip_dialog *dlg, pjsip_endpoint *endpt, pjsip_tx_data **tdata) nogil
int pjsip_inv_create_uas(pjsip_dialog *dlg, pjsip_rx_data *rdata, pjmedia_sdp_session *local_sdp,
unsigned int options, pjsip_inv_session **p_inv) nogil
int pjsip_inv_initial_answer(pjsip_inv_session *inv, pjsip_rx_data *rdata, int st_code,
pj_str_t *st_text, pjmedia_sdp_session *sdp, pjsip_tx_data **p_tdata) nogil
int pjsip_inv_answer(pjsip_inv_session *inv, int st_code, pj_str_t *st_text,
pjmedia_sdp_session *local_sdp, pjsip_tx_data **p_tdata) nogil
int pjsip_inv_create_uac(pjsip_dialog *dlg, pjmedia_sdp_session *local_sdp,
unsigned int options, pjsip_inv_session **p_inv) nogil
int pjsip_inv_invite(pjsip_inv_session *inv, pjsip_tx_data **p_tdata) nogil
char *pjsip_inv_state_name(pjsip_inv_state state) nogil
int pjsip_inv_reinvite(pjsip_inv_session *inv, pj_str_t *new_contact,
pjmedia_sdp_session *new_offer, pjsip_tx_data **p_tdata) nogil
int pjsip_create_sdp_body(pj_pool_t *pool, pjmedia_sdp_session *sdp, pjsip_msg_body **p_body) nogil
# Replaces
struct pjsip_replaces_hdr:
pj_str_t call_id
pj_str_t to_tag
pj_str_t from_tag
int early_only
pjsip_param other_param
pjsip_replaces_hdr *pjsip_replaces_hdr_create(pj_pool_t *pool) nogil
int pjsip_replaces_verify_request(pjsip_rx_data *rdata, pjsip_dialog **p_dlg, int lock_dlg, pjsip_tx_data **p_tdata) nogil
int pjsip_replaces_init_module(pjsip_endpoint *endpt) nogil
# declarations
# core.util
cdef class frozenlist(object):
# attributes
cdef int initialized
cdef list list
cdef long hash
cdef class frozendict(object):
# attributes
cdef int initialized
cdef dict dict
cdef long hash
cdef class PJSTR(object):
# attributes
cdef pj_str_t pj_str
cdef object str
# core.lib
cdef class PJLIB(object):
# attributes
cdef int _init_done
cdef class PJCachingPool(object):
# attributes
cdef pj_caching_pool _obj
cdef int _init_done
cdef class PJSIPEndpoint(object):
# attributes
cdef pjsip_endpoint *_obj
cdef pj_pool_t *_pool
cdef pjsip_transport *_udp_transport
cdef pjsip_tpfactory *_tcp_transport
cdef pjsip_tpfactory *_tls_transport
cdef int _tls_verify_server
cdef PJSTR _tls_ca_file
cdef PJSTR _tls_cert_file
cdef PJSTR _tls_privkey_file
cdef object _local_ip_used
cdef int _tls_timeout
# private methods
cdef int _make_local_addr(self, pj_sockaddr_in *local_addr, object ip_address, int port) except -1
cdef int _start_udp_transport(self, int port) except -1
cdef int _stop_udp_transport(self) except -1
cdef int _start_tcp_transport(self, int port) except -1
cdef int _stop_tcp_transport(self) except -1
cdef int _start_tls_transport(self, port) except -1
cdef int _stop_tls_transport(self) except -1
cdef int _set_dns_nameservers(self, list servers) except -1
cdef class PJMEDIAEndpoint(object):
# attributes
cdef pjmedia_endpt *_obj
cdef pj_pool_t *_pool
cdef int _has_audio_codecs
cdef int _has_video
cdef int _has_ffmpeg_video
cdef int _has_vpx
# private methods
cdef list _get_codecs(self)
cdef list _get_all_codecs(self)
cdef list _get_current_codecs(self)
cdef int _set_codecs(self, list req_codecs) except -1
cdef list _get_video_codecs(self)
cdef list _get_all_video_codecs(self)
cdef list _get_current_video_codecs(self)
cdef int _set_video_codecs(self, list req_codecs) except -1
cdef void _audio_subsystem_init(self, PJCachingPool caching_pool)
cdef void _audio_subsystem_shutdown(self)
cdef void _video_subsystem_init(self, PJCachingPool caching_pool)
cdef void _video_subsystem_shutdown(self)
cdef void _set_h264_options(self, str profile, int level)
cdef void _set_video_options(self, tuple max_resolution, int max_framerate, float max_bitrate)
# core.helper
cdef class BaseCredentials(object):
# attributes
cdef pjsip_cred_info _credentials
# private methods
cdef pjsip_cred_info* get_cred_info(self)
cdef class Credentials(BaseCredentials):
# attributes
cdef str _username
cdef str _realm
cdef str _password
cdef bint _digest
cdef class FrozenCredentials(BaseCredentials):
# attributes
cdef int initialized
cdef readonly str username
cdef readonly str realm
cdef readonly str password
cdef readonly bint digest
cdef class BaseSIPURI(object):
pass
cdef class SIPURI(BaseSIPURI):
# attributes
cdef public object user
cdef public object password
cdef public object host
cdef public bint secure
cdef public dict parameters
cdef public dict headers
cdef object _port
cdef class FrozenSIPURI(BaseSIPURI):
# attributes
cdef int initialized
cdef readonly object user
cdef readonly object password
cdef readonly object host
cdef readonly object port
cdef readonly bint secure
cdef readonly frozendict parameters
cdef readonly frozendict headers
cdef SIPURI SIPURI_create(pjsip_sip_uri *base_uri)
cdef FrozenSIPURI FrozenSIPURI_create(pjsip_sip_uri *base_uri)
# core.headers
cdef class BaseHeader(object):
pass
cdef class Header(BaseHeader):
# attributes
cdef str _name
cdef str _body
cdef class FrozenHeader(BaseHeader):
# attributes
cdef readonly str name
cdef readonly str body
cdef class BaseContactHeader(object):
pass
cdef class ContactHeader(BaseContactHeader):
# attributes
cdef SIPURI _uri
cdef unicode _display_name
cdef dict _parameters
cdef class FrozenContactHeader(BaseContactHeader):
# attributes
cdef int initialized
cdef readonly FrozenSIPURI uri
cdef readonly unicode display_name
cdef readonly frozendict parameters
cdef class BaseContentTypeHeader(object):
pass
cdef class ContentTypeHeader(BaseContentTypeHeader):
# attributes
cdef str _content_type
cdef dict _parameters
cdef class FrozenContentTypeHeader(BaseContentTypeHeader):
# attributes
cdef int initialized
cdef readonly str _content_type
cdef readonly frozendict parameters
cdef class BaseIdentityHeader(object):
pass
cdef class IdentityHeader(BaseIdentityHeader):
# attributes
cdef SIPURI _uri
cdef public unicode display_name
cdef dict _parameters
cdef class FrozenIdentityHeader(BaseIdentityHeader):
# attributes
cdef int initialized
cdef readonly FrozenSIPURI uri
cdef readonly unicode display_name
cdef readonly frozendict parameters
cdef class FromHeader(IdentityHeader):
pass
cdef class FrozenFromHeader(FrozenIdentityHeader):
pass
cdef class ToHeader(IdentityHeader):
pass
cdef class FrozenToHeader(FrozenIdentityHeader):
pass
cdef class RouteHeader(IdentityHeader):
pass
cdef class FrozenRouteHeader(FrozenIdentityHeader):
pass
cdef class RecordRouteHeader(IdentityHeader):
pass
cdef class FrozenRecordRouteHeader(FrozenIdentityHeader):
pass
cdef class BaseRetryAfterHeader(object):
pass
cdef class RetryAfterHeader(BaseRetryAfterHeader):
# attributes
cdef public int seconds
cdef public str comment
cdef dict _parameters
cdef class FrozenRetryAfterHeader(BaseRetryAfterHeader):
# attributes
cdef int initialized
cdef readonly int seconds
cdef readonly str comment
cdef readonly frozendict parameters
cdef class BaseViaHeader(object):
pass
cdef class ViaHeader(BaseViaHeader):
# attributes
cdef str _transport
cdef str _host
cdef int _port
cdef dict _parameters
cdef class FrozenViaHeader(BaseViaHeader):
# attributes
cdef int initialized
cdef readonly str transport
cdef readonly str host
cdef readonly int port
cdef readonly frozendict parameters
cdef class BaseWarningHeader(object):
pass
cdef class WarningHeader(BaseWarningHeader):
# attributes
cdef int _code
cdef str _agent
cdef str _text
cdef class FrozenWarningHeader(BaseWarningHeader):
# attributes
cdef int initialized
cdef readonly int code
cdef readonly str agent
cdef readonly str text
cdef class BaseEventHeader(object):
pass
cdef class EventHeader(BaseEventHeader):
# attributes
cdef public event
cdef dict _parameters
cdef class FrozenEventHeader(BaseEventHeader):
# attributes
cdef int initialized
cdef readonly str event
cdef readonly frozendict parameters
cdef class BaseSubscriptionStateHeader(object):
pass
cdef class SubscriptionStateHeader(BaseSubscriptionStateHeader):
# attributes
cdef public state
cdef dict _parameters
cdef class FrozenSubscriptionStateHeader(BaseSubscriptionStateHeader):
# attributes
cdef int initialized
cdef readonly str state
cdef readonly frozendict parameters
cdef class BaseReasonHeader(object):
pass
cdef class ReasonHeader(BaseReasonHeader):
# attributes
cdef public str protocol
cdef public dict parameters
cdef class FrozenReasonHeader(BaseReasonHeader):
# attributes
cdef int initialized
cdef readonly str protocol
cdef readonly frozendict parameters
cdef class BaseReferToHeader(object):
pass
cdef class ReferToHeader(BaseReferToHeader):
# attributes
cdef public str uri
cdef dict _parameters
cdef class FrozenReferToHeader(BaseReferToHeader):
# attributes
cdef int initialized
cdef readonly str uri
cdef readonly frozendict parameters
cdef class BaseSubjectHeader(object):
pass
cdef class SubjectHeader(BaseSubjectHeader):
# attributes
cdef public unicode subject
cdef class FrozenSubjectHeader(BaseSubjectHeader):
# attributes
cdef int initialized
cdef readonly unicode subject
cdef class BaseReplacesHeader(object):
pass
cdef class ReplacesHeader(BaseReplacesHeader):
# attributes
cdef public str call_id
cdef public str from_tag
cdef public str to_tag
cdef public int early_only
cdef dict _parameters
cdef class FrozenReplacesHeader(BaseReplacesHeader):
# attributes
cdef int initialized
cdef readonly str call_id
cdef readonly str from_tag
cdef readonly str to_tag
cdef readonly int early_only
cdef readonly frozendict parameters
cdef Header Header_create(pjsip_generic_string_hdr *header)
cdef FrozenHeader FrozenHeader_create(pjsip_generic_string_hdr *header)
cdef ContactHeader ContactHeader_create(pjsip_contact_hdr *header)
cdef FrozenContactHeader FrozenContactHeader_create(pjsip_contact_hdr *header)
cdef ContentTypeHeader ContentTypeHeader_create(pjsip_ctype_hdr *header)
cdef FrozenContentTypeHeader FrozenContentTypeHeader_create(pjsip_ctype_hdr *header)
cdef FromHeader FromHeader_create(pjsip_fromto_hdr *header)
cdef FrozenFromHeader FrozenFromHeader_create(pjsip_fromto_hdr *header)
cdef ToHeader ToHeader_create(pjsip_fromto_hdr *header)
cdef FrozenToHeader FrozenToHeader_create(pjsip_fromto_hdr *header)
cdef RouteHeader RouteHeader_create(pjsip_routing_hdr *header)
cdef FrozenRouteHeader FrozenRouteHeader_create(pjsip_routing_hdr *header)
cdef RecordRouteHeader RecordRouteHeader_create(pjsip_routing_hdr *header)
cdef FrozenRecordRouteHeader FrozenRecordRouteHeader_create(pjsip_routing_hdr *header)
cdef RetryAfterHeader RetryAfterHeader_create(pjsip_retry_after_hdr *header)
cdef FrozenRetryAfterHeader FrozenRetryAfterHeader_create(pjsip_retry_after_hdr *header)
cdef ViaHeader ViaHeader_create(pjsip_via_hdr *header)
cdef FrozenViaHeader FrozenViaHeader_create(pjsip_via_hdr *header)
cdef EventHeader EventHeader_create(pjsip_event_hdr *header)
cdef FrozenEventHeader FrozenEventHeader_create(pjsip_event_hdr *header)
cdef SubscriptionStateHeader SubscriptionStateHeader_create(pjsip_sub_state_hdr *header)
cdef FrozenSubscriptionStateHeader FrozenSubscriptionStateHeader_create(pjsip_sub_state_hdr *header)
cdef ReferToHeader ReferToHeader_create(pjsip_generic_string_hdr *header)
cdef FrozenReferToHeader FrozenReferToHeader_create(pjsip_generic_string_hdr *header)
cdef SubjectHeader SubjectHeader_create(pjsip_generic_string_hdr *header)
cdef FrozenSubjectHeader FrozenSubjectHeader_create(pjsip_generic_string_hdr *header)
cdef ReplacesHeader ReplacesHeader_create(pjsip_replaces_hdr *header)
cdef FrozenReplacesHeader FrozenReplacesHeader_create(pjsip_replaces_hdr *header)
# core.util
cdef int _str_to_pj_str(object string, pj_str_t *pj_str) except -1
cdef object _pj_str_to_bytes(pj_str_t pj_bytes)
cdef object _pj_str_to_str(pj_str_t pj_str)
cdef object _pj_status_to_str(int status)
cdef object _pj_status_to_def(int status)
+cdef object _buf_to_str(object buf)
+cdef object _str_as_str(object string)
+cdef object _str_as_size(object string)
+
+
cdef dict _pjsip_param_to_dict(pjsip_param *param_list)
cdef int _dict_to_pjsip_param(object params, pjsip_param *param_list, pj_pool_t *pool)
cdef int _pjsip_msg_to_dict(pjsip_msg *msg, dict info_dict) except -1
cdef int _is_valid_ip(int af, object ip) except -1
cdef int _get_ip_version(object ip) except -1
cdef int _add_headers_to_tdata(pjsip_tx_data *tdata, object headers) except -1
cdef int _remove_headers_from_tdata(pjsip_tx_data *tdata, object headers) except -1
cdef int _BaseSIPURI_to_pjsip_sip_uri(BaseSIPURI uri, pjsip_sip_uri *pj_uri, pj_pool_t *pool) except -1
cdef int _BaseRouteHeader_to_pjsip_route_hdr(BaseIdentityHeader header, pjsip_route_hdr *pj_header, pj_pool_t *pool) except -1
# core.ua
ctypedef int (*timer_callback)(object, object) except -1
cdef class Timer(object):
# attributes
cdef int _scheduled
cdef double schedule_time
cdef timer_callback callback
cdef object obj
# private methods
cdef int schedule(self, float delay, timer_callback callback, object obj) except -1
cdef int cancel(self) except -1
cdef int call(self) except -1
cdef class PJSIPThread(object):
# attributes
cdef pj_thread_t *_obj
cdef long _thread_desc[PJ_THREAD_DESC_SIZE]
cdef class PJSIPUA(object):
# attributes
cdef object _threads
cdef object _event_handler
cdef list _timers
cdef PJLIB _pjlib
cdef PJCachingPool _caching_pool
cdef PJSIPEndpoint _pjsip_endpoint
cdef PJMEDIAEndpoint _pjmedia_endpoint
cdef pjsip_module _module
cdef PJSTR _module_name
cdef pjsip_module _opus_fix_module
cdef PJSTR _opus_fix_module_name
cdef pjsip_module _trace_module
cdef PJSTR _trace_module_name
cdef pjsip_module _ua_tag_module
cdef PJSTR _ua_tag_module_name
cdef pjsip_module _event_module
cdef PJSTR _event_module_name
cdef int _trace_sip
cdef int _detect_sip_loops
cdef int _enable_colorbar_device
cdef PJSTR _user_agent
cdef object _events
cdef object _sent_messages
cdef object _ip_address
cdef int _rtp_port_start
cdef int _rtp_port_count
cdef int _rtp_port_usable_count
cdef int _rtp_port_index
cdef pj_stun_config _stun_cfg
cdef int _fatal_error
cdef set _incoming_events
cdef set _incoming_requests
cdef pj_rwmutex_t *audio_change_rwlock
cdef pj_mutex_t *video_lock
cdef list old_devices
cdef list old_video_devices
cdef object _zrtp_cache
# private methods
cdef object _get_sound_devices(self, int is_output)
cdef object _get_default_sound_device(self, int is_output)
cdef object _get_video_devices(self)
cdef object _get_default_video_device(self)
cdef int _poll_log(self) except -1
cdef int _handle_exception(self, int is_fatal) except -1
cdef int _check_self(self) except -1
cdef int _check_thread(self) except -1
cdef int _add_timer(self, Timer timer) except -1
cdef int _remove_timer(self, Timer timer) except -1
cdef int _cb_rx_request(self, pjsip_rx_data *rdata) except 0
cdef pj_pool_t* create_memory_pool(self, bytes name, int initial_size, int resize_size)
cdef void release_memory_pool(self, pj_pool_t* pool)
cdef void reset_memory_pool(self, pj_pool_t* pool)
cdef int _PJSIPUA_cb_rx_request(pjsip_rx_data *rdata) with gil
cdef void _cb_detect_nat_type(void *user_data, pj_stun_nat_detect_result_ptr_const res) with gil
cdef int _cb_opus_fix_tx(pjsip_tx_data *tdata) with gil
cdef int _cb_trace_rx(pjsip_rx_data *rdata) with gil
cdef int _cb_trace_tx(pjsip_tx_data *tdata) with gil
cdef int _cb_add_user_agent_hdr(pjsip_tx_data *tdata) with gil
cdef int _cb_add_server_hdr(pjsip_tx_data *tdata) with gil
cdef PJSIPUA _get_ua()
cdef int deallocate_weakref(object weak_ref, object timer) except -1 with gil
# core.sound
cdef class AudioMixer(object):
# attributes
cdef int _input_volume
cdef int _output_volume
cdef bint _muted
cdef pj_mutex_t *_lock
cdef pj_pool_t *_conf_pool
cdef pj_pool_t *_snd_pool
cdef pjmedia_conf *_obj
cdef pjmedia_master_port *_master_port
cdef pjmedia_port *_null_port
cdef pjmedia_snd_port *_snd
cdef list _connected_slots
cdef readonly int ec_tail_length
cdef readonly int sample_rate
cdef readonly int slot_count
cdef readonly int used_slot_count
cdef readonly unicode input_device
cdef readonly unicode output_device
cdef readonly unicode real_input_device
cdef readonly unicode real_output_device
# private methods
cdef void _start_sound_device(self, PJSIPUA ua, unicode input_device, unicode output_device, int ec_tail_length)
cdef void _stop_sound_device(self, PJSIPUA ua)
cdef int _add_port(self, PJSIPUA ua, pj_pool_t *pool, pjmedia_port *port) except -1 with gil
cdef int _remove_port(self, PJSIPUA ua, unsigned int slot) except -1 with gil
cdef int _cb_postpoll_stop_sound(self, timer) except -1
cdef class ToneGenerator(object):
# attributes
cdef int _slot
cdef int _volume
cdef pj_mutex_t *_lock
cdef pj_pool_t *_pool
cdef pjmedia_port *_obj
cdef Timer _timer
cdef readonly AudioMixer mixer
# private methods
cdef PJSIPUA _get_ua(self, int raise_exception)
cdef int _stop(self, PJSIPUA ua) except -1
cdef int _cb_check_done(self, timer) except -1
cdef class RecordingWaveFile(object):
# attributes
cdef int _slot
cdef int _was_started
cdef pj_mutex_t *_lock
cdef pj_pool_t *_pool
cdef pjmedia_port *_port
cdef readonly str filename
cdef readonly AudioMixer mixer
# private methods
cdef PJSIPUA _check_ua(self)
cdef int _stop(self, PJSIPUA ua) except -1
cdef class WaveFile(object):
# attributes
cdef object __weakref__
cdef object weakref
cdef int _slot
cdef int _volume
cdef pj_mutex_t *_lock
cdef pj_pool_t *_pool
cdef pjmedia_port *_port
cdef readonly str filename
cdef readonly AudioMixer mixer
# private methods
cdef PJSIPUA _check_ua(self)
cdef int _stop(self, PJSIPUA ua, int notify) except -1
cdef int _cb_eof(self, timer) except -1
cdef class MixerPort(object):
cdef int _slot
cdef int _was_started
cdef pj_mutex_t *_lock
cdef pj_pool_t *_pool
cdef pjmedia_port *_port
cdef readonly AudioMixer mixer
# private methods
cdef PJSIPUA _check_ua(self)
cdef int _stop(self, PJSIPUA ua) except -1
cdef int _AudioMixer_dealloc_handler(object obj) except -1
cdef int cb_play_wav_eof(pjmedia_port *port, void *user_data) with gil
# core.video
cdef class VideoFrame(object):
cdef readonly str data
cdef readonly int width
cdef readonly int height
cdef class VideoConsumer(object):
cdef pjmedia_port *consumer_port
cdef pjmedia_vid_port *_video_port
cdef pj_pool_t *_pool
cdef pj_mutex_t *_lock
cdef int _running
cdef int _closed
cdef VideoProducer _producer
cdef object __weakref__
cdef object weakref
cdef void _set_producer(self, VideoProducer producer)
cdef class VideoProducer(object):
cdef pjmedia_port *producer_port
cdef pjmedia_vid_port *_video_port
cdef pj_pool_t *_pool
cdef pj_mutex_t *_lock
cdef int _running
cdef int _started
cdef int _closed
cdef object _consumers
cdef void _add_consumer(self, VideoConsumer consumer)
cdef void _remove_consumer(self, VideoConsumer consumer)
cdef class VideoCamera(VideoProducer):
cdef pjmedia_port *_video_tee
cdef readonly unicode name
cdef readonly unicode real_name
cdef void _start(self)
cdef void _stop(self)
cdef class FrameBufferVideoRenderer(VideoConsumer):
cdef pjmedia_vid_dev_stream *_video_stream
cdef object _frame_handler
cdef _initialize(self, VideoProducer producer)
cdef void _destroy_video_port(self)
cdef void _start(self)
cdef void _stop(self)
cdef class LocalVideoStream(VideoConsumer):
cdef void _initialize(self, pjmedia_port *media_port)
cdef class RemoteVideoStream(VideoProducer):
cdef pjmedia_vid_stream *_video_stream
cdef object _event_handler
cdef void _initialize(self, pjmedia_vid_stream *stream)
cdef LocalVideoStream_create(pjmedia_vid_stream *stream)
cdef RemoteVideoStream_create(pjmedia_vid_stream *stream, format_change_handler=*)
cdef int RemoteVideoStream_on_event(pjmedia_event *event, void *user_data) with gil
cdef void _start_video_port(pjmedia_vid_port *port)
cdef void _stop_video_port(pjmedia_vid_port *port)
# core.event
cdef struct _core_event
cdef struct _handler_queue
cdef int _event_queue_append(_core_event *event)
cdef void _cb_log(int level, char_ptr_const data, int len)
cdef int _add_event(object event_name, dict params) except -1
cdef list _get_clear_event_queue()
cdef int _add_handler(int func(object obj) except -1, object obj, _handler_queue *queue) except -1
cdef int _remove_handler(object obj, _handler_queue *queue) except -1
cdef int _process_handler_queue(PJSIPUA ua, _handler_queue *queue) except -1
# core.request
cdef class EndpointAddress(object):
# attributes
cdef readonly bytes ip
cdef readonly int port
cdef class Request(object):
# attributes
cdef readonly object state
cdef PJSTR _method
cdef readonly EndpointAddress peer_address
cdef readonly FrozenCredentials credentials
cdef readonly FrozenFromHeader from_header
cdef readonly FrozenToHeader to_header
cdef readonly FrozenSIPURI request_uri
cdef readonly FrozenContactHeader contact_header
cdef readonly FrozenRouteHeader route_header
cdef PJSTR _call_id
cdef readonly int cseq
cdef readonly frozenlist extra_headers
cdef PJSTR _content_type
cdef PJSTR _content_subtype
cdef PJSTR _body
cdef pjsip_tx_data *_tdata
cdef pjsip_transaction *_tsx
cdef pjsip_auth_clt_sess _auth
cdef pjsip_route_hdr _route_header
cdef int _need_auth
cdef pj_timer_entry _timer
cdef int _timer_active
cdef int _expire_rest
cdef object _expire_time
cdef object _timeout
# private methods
cdef PJSIPUA _get_ua(self)
cdef int _cb_tsx_state(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef int _cb_timer(self, PJSIPUA ua) except -1
cdef class IncomingRequest(object):
# attributes
cdef readonly str state
cdef pjsip_transaction *_tsx
cdef pjsip_tx_data *_tdata
cdef readonly EndpointAddress peer_address
# methods
cdef int init(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef void _Request_cb_tsx_state(pjsip_transaction *tsx, pjsip_event *event) with gil
cdef void _Request_cb_timer(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) with gil
# core.referral
cdef class Referral(object):
# attributes
cdef pjsip_evsub *_obj
cdef pjsip_dialog *_dlg
cdef pjsip_route_hdr _route_header
cdef pj_list _route_set
cdef int _create_subscription
cdef readonly object state
cdef pj_timer_entry _timeout_timer
cdef int _timeout_timer_active
cdef pj_timer_entry _refresh_timer
cdef int _refresh_timer_active
cdef readonly EndpointAddress peer_address
cdef readonly FrozenFromHeader from_header
cdef readonly FrozenToHeader to_header
cdef readonly FrozenReferToHeader refer_to_header
cdef readonly FrozenRouteHeader route_header
cdef readonly FrozenCredentials credentials
cdef readonly FrozenContactHeader local_contact_header
cdef readonly FrozenContactHeader remote_contact_header
cdef readonly int refresh
cdef readonly frozenlist extra_headers
cdef pj_time_val _request_timeout
cdef int _want_end
cdef int _term_code
cdef object _term_reason
# private methods
cdef PJSIPUA _get_ua(self)
cdef int _update_contact_header(self, BaseContactHeader contact_header) except -1
cdef int _cancel_timers(self, PJSIPUA ua, int cancel_timeout, int cancel_refresh) except -1
cdef int _send_refer(self, PJSIPUA ua, pj_time_val *timeout, FrozenReferToHeader refer_to_header, frozenlist extra_headers) except -1
cdef int _send_subscribe(self, PJSIPUA ua, int expires, pj_time_val *timeout, frozenlist extra_headers) except -1
cdef int _cb_state(self, PJSIPUA ua, object state, int code, str reason) except -1
cdef int _cb_got_response(self, PJSIPUA ua, pjsip_rx_data *rdata, str method) except -1
cdef int _cb_notify(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef int _cb_timeout_timer(self, PJSIPUA ua)
cdef int _cb_refresh_timer(self, PJSIPUA ua)
cdef class IncomingReferral(object):
cdef pjsip_evsub *_obj
cdef pjsip_dialog *_dlg
cdef pjsip_tx_data *_initial_response
cdef pjsip_transaction *_initial_tsx
cdef pj_time_val _expires_time
cdef int _create_subscription
cdef readonly str state
cdef readonly EndpointAddress peer_address
cdef readonly FrozenContactHeader local_contact_header
cdef readonly FrozenContactHeader remote_contact_header
cdef PJSTR _content
cdef int init(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef PJSIPUA _get_ua(self, int raise_exception)
cdef int _set_content(self, int code, str reason) except -1
cdef int _set_state(self, str state) except -1
cdef int _send_initial_response(self, int code) except -1
cdef int _send_notify(self) except -1
cdef int _terminate(self, PJSIPUA ua, int do_cleanup) except -1
cdef int _cb_rx_refresh(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef int _cb_server_timeout(self, PJSIPUA ua) except -1
cdef int _cb_tsx(self, PJSIPUA ua, pjsip_event *event) except -1
cdef void _Referral_cb_state(pjsip_evsub *sub, pjsip_event *event) with gil
cdef void _Referral_cb_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil
cdef void _Referral_cb_refresh(pjsip_evsub *sub) with gil
cdef void _IncomingReferral_cb_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil
cdef void _IncomingReferral_cb_server_timeout(pjsip_evsub *sub) with gil
cdef void _IncomingReferral_cb_tsx(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) with gil
# core.subscription
cdef class Subscription(object):
# attributes
cdef pjsip_evsub *_obj
cdef pjsip_dialog *_dlg
cdef pjsip_route_hdr _route_header
cdef pj_list _route_set
cdef pj_timer_entry _timeout_timer
cdef int _timeout_timer_active
cdef pj_timer_entry _refresh_timer
cdef int _refresh_timer_active
cdef readonly object state
cdef readonly EndpointAddress peer_address
cdef readonly FrozenFromHeader from_header
cdef readonly FrozenToHeader to_header
cdef readonly FrozenContactHeader contact_header
cdef readonly object event
cdef readonly FrozenRouteHeader route_header
cdef readonly FrozenCredentials credentials
cdef readonly int refresh
cdef readonly frozenlist extra_headers
cdef readonly object body
cdef readonly object content_type
cdef readonly str call_id
cdef pj_time_val _subscribe_timeout
cdef int _want_end
cdef int _term_code
cdef object _term_reason
cdef int _expires
# private methods
cdef PJSIPUA _get_ua(self)
cdef int _cancel_timers(self, PJSIPUA ua, int cancel_timeout, int cancel_refresh) except -1
cdef int _send_subscribe(self, PJSIPUA ua, int expires, pj_time_val *timeout,
object extra_headers, object content_type, object body) except -1
cdef int _cb_state(self, PJSIPUA ua, object state, int code, object reason, dict headers) except -1
cdef int _cb_got_response(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef int _cb_notify(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef int _cb_timeout_timer(self, PJSIPUA ua)
cdef int _cb_refresh_timer(self, PJSIPUA ua)
cdef class IncomingSubscription(object):
# attributes
cdef pjsip_evsub *_obj
cdef pjsip_dialog *_dlg
cdef PJSTR _content_type
cdef PJSTR _content_subtype
cdef PJSTR _content
cdef pjsip_tx_data *_initial_response
cdef pjsip_transaction *_initial_tsx
cdef int _expires
cdef readonly str state
cdef readonly str event
cdef readonly str call_id
cdef readonly EndpointAddress peer_address
# methods
cdef int _set_state(self, str state) except -1
cdef PJSIPUA _get_ua(self, int raise_exception)
cdef int init(self, PJSIPUA ua, pjsip_rx_data *rdata, str event) except -1
cdef int _send_initial_response(self, int code) except -1
cdef int _send_notify(self, str reason=*) except -1
cdef int _terminate(self, PJSIPUA ua, str reason, int do_cleanup) except -1
cdef int _cb_rx_refresh(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef int _cb_server_timeout(self, PJSIPUA ua) except -1
cdef int _cb_tsx(self, PJSIPUA ua, pjsip_event *event) except -1
cdef void _Subscription_cb_state(pjsip_evsub *sub, pjsip_event *event) with gil
cdef void _Subscription_cb_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil
cdef void _Subscription_cb_refresh(pjsip_evsub *sub) with gil
cdef void _IncomingSubscription_cb_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata,
int *p_st_code, pj_str_t **p_st_text,
pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil
cdef void _IncomingSubscription_cb_server_timeout(pjsip_evsub *sub) with gil
cdef void _IncomingSubscription_cb_tsx(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) with gil
# core.sdp
cdef class BaseSDPConnection(object):
# attributes
cdef pjmedia_sdp_conn _sdp_connection
# private methods
cdef pjmedia_sdp_conn* get_sdp_connection(self)
cdef class SDPConnection(BaseSDPConnection):
# attributes
cdef str _address
cdef str _net_type
cdef str _address_type
cdef class FrozenSDPConnection(BaseSDPConnection):
# attributes
cdef int initialized
cdef readonly str address
cdef readonly str net_type
cdef readonly str address_type
cdef class SDPAttributeList(list):
pass
cdef class FrozenSDPAttributeList(frozenlist):
pass
cdef class SDPBandwidthInfoList(list):
pass
cdef class FrozenSDPBandwidthInfoList(frozenlist):
pass
cdef class BaseSDPSession(object):
# attributes
cdef pjmedia_sdp_session _sdp_session
# private methods
cdef pjmedia_sdp_session* get_sdp_session(self)
cdef class SDPSession(BaseSDPSession):
# attributes
cdef str _address
cdef str _user
cdef str _net_type
cdef str _address_type
cdef str _name
cdef str _info
cdef SDPConnection _connection
cdef list _attributes
cdef list _bandwidth_info
cdef list _media
# private methods
cdef int _update(self) except -1
cdef class FrozenSDPSession(BaseSDPSession):
# attributes
cdef int initialized
cdef readonly str address
cdef readonly unsigned int id
cdef readonly unsigned int version
cdef readonly str user
cdef readonly str net_type
cdef readonly str address_type
cdef readonly str name
cdef readonly str info
cdef readonly FrozenSDPConnection connection
cdef readonly int start_time
cdef readonly int stop_time
cdef readonly FrozenSDPAttributeList attributes
cdef readonly FrozenSDPBandwidthInfoList bandwidth_info
cdef readonly frozenlist media
cdef class BaseSDPMediaStream(object):
# attributes
cdef pjmedia_sdp_media _sdp_media
# private methods
cdef pjmedia_sdp_media* get_sdp_media(self)
cdef class SDPMediaStream(BaseSDPMediaStream):
# attributes
cdef str _media
cdef str _transport
cdef list _formats
cdef list _codec_list
cdef str _info
cdef SDPConnection _connection
cdef SDPAttributeList _attributes
cdef SDPBandwidthInfoList _bandwidth_info
# private methods
cdef int _update(self, SDPMediaStream media) except -1
cdef class FrozenSDPMediaStream(BaseSDPMediaStream):
# attributes
cdef int initialized
cdef readonly str media
cdef readonly int port
cdef readonly str transport
cdef readonly int port_count
cdef readonly frozenlist formats
cdef readonly frozenlist codec_list
cdef readonly str info
cdef readonly FrozenSDPConnection connection
cdef readonly FrozenSDPAttributeList attributes
cdef readonly FrozenSDPBandwidthInfoList bandwidth_info
cdef class BaseSDPAttribute(object):
# attributes
cdef pjmedia_sdp_attr _sdp_attribute
# private methods
cdef pjmedia_sdp_attr* get_sdp_attribute(self)
cdef class SDPAttribute(BaseSDPAttribute):
# attributes
cdef str _name
cdef str _value
cdef class FrozenSDPAttribute(BaseSDPAttribute):
# attributes
cdef int initialized
cdef readonly str name
cdef readonly str value
cdef class BaseSDPBandwidthInfo(object):
# attributes
cdef pjmedia_sdp_bandw _sdp_bandwidth_info
# private methods
cdef pjmedia_sdp_bandw* get_sdp_bandwidth_info(self)
cdef class SDPBandwidthInfo(BaseSDPBandwidthInfo):
# attributes
cdef str _modifier
cdef int _value
cdef class FrozenSDPBandwidthInfo(BaseSDPBandwidthInfo):
# attributes
cdef int initialized
cdef readonly str modifier
cdef readonly int value
cdef SDPSession SDPSession_create(pjmedia_sdp_session_ptr_const pj_session)
cdef FrozenSDPSession FrozenSDPSession_create(pjmedia_sdp_session_ptr_const pj_session)
cdef SDPMediaStream SDPMediaStream_create(pjmedia_sdp_media *pj_media)
cdef FrozenSDPMediaStream FrozenSDPMediaStream_create(pjmedia_sdp_media *pj_media)
cdef SDPConnection SDPConnection_create(pjmedia_sdp_conn *pj_conn)
cdef FrozenSDPConnection FrozenSDPConnection_create(pjmedia_sdp_conn *pj_conn)
cdef SDPAttribute SDPAttribute_create(pjmedia_sdp_attr *pj_attr)
cdef FrozenSDPAttribute FrozenSDPAttribute_create(pjmedia_sdp_attr *pj_attr)
cdef SDPBandwidthInfo SDPBandwidthInfo_create(pjmedia_sdp_bandw *pj_bandw)
cdef FrozenSDPBandwidthInfo FrozenSDPBandwidthInfo_create(pjmedia_sdp_bandw *pj_bandw)
cdef class SDPNegotiator(object):
# attributes
cdef pjmedia_sdp_neg* _neg
cdef pj_pool_t *_pool
# core.invitation
cdef class SDPPayloads:
cdef readonly FrozenSDPSession proposed_local
cdef readonly FrozenSDPSession proposed_remote
cdef readonly FrozenSDPSession active_local
cdef readonly FrozenSDPSession active_remote
cdef class StateCallbackTimer(Timer):
cdef object state
cdef object sub_state
cdef object rdata
cdef object tdata
cdef object originator
cdef class SDPCallbackTimer(Timer):
cdef int status
cdef object active_local
cdef object active_remote
cdef class TransferStateCallbackTimer(Timer):
cdef object state
cdef object code
cdef object reason
cdef class TransferResponseCallbackTimer(Timer):
cdef object method
cdef object rdata
cdef class TransferRequestCallbackTimer(Timer):
cdef object rdata
cdef class Invitation(object):
# attributes
cdef object __weakref__
cdef object weakref
cdef int _sdp_neg_status
cdef int _failed_response
cdef pj_list _route_set
cdef pj_mutex_t *_lock
cdef pjsip_inv_session *_invite_session
cdef pjsip_evsub *_transfer_usage
cdef pjsip_role_e _transfer_usage_role
cdef pjsip_dialog *_dialog
cdef pjsip_route_hdr _route_header
cdef pjsip_transaction *_reinvite_transaction
cdef PJSTR _sipfrag_payload
cdef Timer _timer
cdef Timer _transfer_timeout_timer
cdef Timer _transfer_refresh_timer
cdef readonly str call_id
cdef readonly str direction
cdef readonly str remote_user_agent
cdef readonly str state
cdef readonly str sub_state
cdef readonly str transport
cdef readonly str transfer_state
cdef readonly EndpointAddress peer_address
cdef readonly FrozenCredentials credentials
cdef readonly FrozenContactHeader local_contact_header
cdef readonly FrozenContactHeader remote_contact_header
cdef readonly FrozenFromHeader from_header
cdef readonly FrozenToHeader to_header
cdef readonly FrozenSIPURI request_uri
cdef readonly FrozenRouteHeader route_header
cdef readonly SDPPayloads sdp
# private methods
cdef int init_incoming(self, PJSIPUA ua, pjsip_rx_data *rdata, unsigned int inv_options) except -1
cdef int process_incoming_transfer(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef int process_incoming_options(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1
cdef PJSIPUA _check_ua(self)
cdef int _do_dealloc(self) except -1
cdef int _update_contact_header(self, BaseContactHeader contact_header) except -1
cdef int _fail(self, PJSIPUA ua) except -1
cdef int _cb_state(self, StateCallbackTimer timer) except -1
cdef int _cb_sdp_done(self, SDPCallbackTimer timer) except -1
cdef int _cb_timer_disconnect(self, timer) except -1
cdef int _cb_postpoll_fail(self, timer) except -1
cdef int _start_incoming_transfer(self, timer) except -1
cdef int _terminate_transfer(self) except -1
cdef int _terminate_transfer_uac(self) except -1
cdef int _terminate_transfer_uas(self) except -1
cdef int _set_transfer_state(self, str state) except -1
cdef int _set_sipfrag_payload(self, int code, str reason) except -1
cdef int _send_notify(self) except -1
cdef int _transfer_cb_timeout_timer(self, timer) except -1
cdef int _transfer_cb_refresh_timer(self, timer) except -1
cdef int _transfer_cb_state(self, TransferStateCallbackTimer timer) except -1
cdef int _transfer_cb_response(self, TransferResponseCallbackTimer timer) except -1
cdef int _transfer_cb_notify(self, TransferRequestCallbackTimer timer) except -1
cdef int _transfer_cb_server_timeout(self, timer) except -1
cdef void _Invitation_cb_state(pjsip_inv_session *inv, pjsip_event *e) with gil
cdef void _Invitation_cb_sdp_done(pjsip_inv_session *inv, int status) with gil
cdef int _Invitation_cb_rx_reinvite(pjsip_inv_session *inv, pjmedia_sdp_session_ptr_const offer, pjsip_rx_data *rdata) with gil
cdef void _Invitation_cb_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) with gil
cdef void _Invitation_cb_new(pjsip_inv_session *inv, pjsip_event *e) with gil
cdef void _Invitation_transfer_cb_state(pjsip_evsub *sub, pjsip_event *event) with gil
cdef void _Invitation_transfer_cb_tsx(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) with gil
cdef void _Invitation_transfer_cb_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil
cdef void _Invitation_transfer_cb_refresh(pjsip_evsub *sub) with gil
cdef void _Invitation_transfer_in_cb_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil
cdef void _Invitation_transfer_in_cb_server_timeout(pjsip_evsub *sub) with gil
# core.mediatransport
cdef class ICECandidate(object):
# attributes
cdef readonly str component
cdef readonly str type
cdef readonly str address
cdef readonly int port
cdef readonly int priority
cdef readonly str rel_address
cdef class ICECheck(object):
cdef readonly ICECandidate local_candidate
cdef readonly ICECandidate remote_candidate
cdef readonly str state
cdef readonly int nominated
cdef class RTPTransport(object):
# attributes
cdef object __weakref__
cdef object weakref
cdef int _af
cdef pj_mutex_t *_lock
cdef pj_pool_t *_pool
cdef pjmedia_transport *_obj
cdef pjmedia_transport *_wrapped_transport
cdef ICECheck _rtp_valid_pair
cdef str _encryption
cdef readonly object ice_stun_address
cdef readonly object ice_stun_port
cdef readonly object state
cdef readonly object use_ice
# private methods
cdef PJSIPUA _check_ua(self)
cdef void _get_info(self, pjmedia_transport_info *info)
cdef int _init_local_sdp(self, BaseSDPSession local_sdp, BaseSDPSession remote_sdp, int sdp_index)
cdef int _ice_active(self)
cdef class MediaCheckTimer(Timer):
# attributes
cdef int media_check_interval
cdef class SDPInfo(object):
# attributes
cdef BaseSDPMediaStream _local_media
cdef BaseSDPSession _local_sdp
cdef BaseSDPSession _remote_sdp
cdef public int index
cdef class AudioTransport(object):
# attributes
cdef object __weakref__
cdef object weakref
cdef int _is_offer
cdef int _is_started
cdef int _slot
cdef int _volume
cdef unsigned int _packets_received
cdef unsigned int _vad
cdef pj_mutex_t *_lock
cdef pj_pool_t *_pool
cdef pjmedia_stream *_obj
cdef pjmedia_stream_info _stream_info
cdef Timer _timer
cdef readonly object direction
cdef readonly AudioMixer mixer
cdef readonly RTPTransport transport
cdef SDPInfo _sdp_info
# private methods
cdef PJSIPUA _check_ua(self)
cdef int _cb_check_rtp(self, MediaCheckTimer timer) except -1
cdef class VideoTransport(object):
# attributes
cdef object __weakref__
cdef object weakref
cdef int _is_offer
cdef int _is_started
cdef unsigned int _packets_received
cdef pj_mutex_t *_lock
cdef pj_pool_t *_pool
cdef pjmedia_vid_stream *_obj
cdef pjmedia_vid_stream_info _stream_info
cdef Timer _timer
cdef readonly object direction
cdef readonly RTPTransport transport
cdef SDPInfo _sdp_info
cdef readonly LocalVideoStream local_video
cdef readonly RemoteVideoStream remote_video
# private methods
cdef PJSIPUA _check_ua(self)
cdef int _cb_check_rtp(self, MediaCheckTimer timer) except -1
cdef void _RTPTransport_cb_ice_complete(pjmedia_transport *tp, pj_ice_strans_op op, int status) with gil
cdef void _RTPTransport_cb_ice_state(pjmedia_transport *tp, pj_ice_strans_state prev, pj_ice_strans_state curr) with gil
cdef void _RTPTransport_cb_ice_stop(pjmedia_transport *tp, char *reason, int err) with gil
cdef void _RTPTransport_cb_zrtp_secure_on(pjmedia_transport *tp, char* cipher) with gil
cdef void _RTPTransport_cb_zrtp_secure_off(pjmedia_transport *tp) with gil
cdef void _RTPTransport_cb_zrtp_show_sas(pjmedia_transport *tp, char* sas, int verified) with gil
cdef void _RTPTransport_cb_zrtp_confirm_goclear(pjmedia_transport *tp) with gil
cdef void _RTPTransport_cb_zrtp_show_message(pjmedia_transport *tp, int severity, int subCode) with gil
cdef void _RTPTransport_cb_zrtp_negotiation_failed(pjmedia_transport *tp, int severity, int subCode) with gil
cdef void _RTPTransport_cb_zrtp_not_supported_by_other(pjmedia_transport *tp) with gil
cdef void _RTPTransport_cb_zrtp_ask_enrollment(pjmedia_transport *tp, int info) with gil
cdef void _RTPTransport_cb_zrtp_inform_enrollment(pjmedia_transport *tp, int info) with gil
cdef void _AudioTransport_cb_dtmf(pjmedia_stream *stream, void *user_data, int digit) with gil
cdef ICECandidate ICECandidate_create(pj_ice_sess_cand *cand)
cdef ICECheck ICECheck_create(pj_ice_sess_check *check)
cdef str _ice_state_to_str(int state)
cdef dict _extract_ice_session_data(pj_ice_sess *ice_sess)
cdef object _extract_rtp_transport(pjmedia_transport *tp)
cdef dict _pj_math_stat_to_dict(pj_math_stat *stat)
cdef dict _pjmedia_rtcp_stream_stat_to_dict(pjmedia_rtcp_stream_stat *stream_stat)
diff --git a/sipsimple/core/_core.referral.pxi b/sipsimple/core/_core.referral.pxi
index f3d8c619..50eb6f67 100644
--- a/sipsimple/core/_core.referral.pxi
+++ b/sipsimple/core/_core.referral.pxi
@@ -1,1003 +1,1003 @@
import re
cdef class Referral:
expire_warning_time = 30
def __cinit__(self, *args, **kwargs):
self.state = "NULL"
pj_timer_entry_init(&self._timeout_timer, 0, <void *> self, _Referral_cb_timer)
self._timeout_timer_active = 0
pj_timer_entry_init(&self._refresh_timer, 1, <void *> self, _Referral_cb_timer)
self._refresh_timer_active = 0
self.extra_headers = frozenlist()
self.peer_address = None
self._create_subscription = 1
self.local_contact_header = None
self.remote_contact_header = None
def __init__(self, SIPURI request_uri not None, FromHeader from_header not None, ToHeader to_header not None, ReferToHeader refer_to_header not None,
ContactHeader contact_header not None, RouteHeader route_header not None, Credentials credentials=None):
global _refer_cb
global _refer_event
cdef PJSTR from_header_str
cdef PJSTR to_header_str
cdef PJSTR contact_str
cdef PJSTR request_uri_str
cdef pjsip_cred_info *cred_info
cdef PJSIPUA ua = _get_ua()
cdef int status
if self._obj != NULL or self.state != "NULL":
raise SIPCoreError("Referral.__init__() was already called")
self.local_contact_header = FrozenContactHeader.new(contact_header)
self.route_header = FrozenRouteHeader.new(route_header)
self.route_header.uri.parameters.dict["lr"] = None # always send lr parameter in Route header
self.route_header.uri.parameters.dict["hide"] = None # always hide Route header
if credentials is not None:
self.credentials = FrozenCredentials.new(credentials)
from_header_parameters = from_header.parameters.copy()
from_header_parameters.pop("tag", None)
from_header.parameters = {}
from_header_str = PJSTR(from_header.body)
to_header_parameters = to_header.parameters.copy()
to_header_parameters.pop("tag", None)
to_header.parameters = {}
to_header_str = PJSTR(to_header.body)
contact_str = PJSTR(str(contact_header.body))
request_uri_str = PJSTR(str(request_uri))
with nogil:
status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from_header_str.pj_str, &contact_str.pj_str,
&to_header_str.pj_str, &request_uri_str.pj_str, &self._dlg)
if status != 0:
raise PJSIPError("Could not create dialog for REFER", status)
# Increment dialog session count so that it's never destroyed by PJSIP
with nogil:
status = pjsip_dlg_inc_session(self._dlg, &ua._module)
if contact_header.expires is not None:
self._dlg.local.contact.expires = contact_header.expires
if contact_header.q is not None:
self._dlg.local.contact.q1000 = int(contact_header.q*1000)
contact_parameters = contact_header.parameters.copy()
contact_parameters.pop("q", None)
contact_parameters.pop("expires", None)
_dict_to_pjsip_param(contact_parameters, &self._dlg.local.contact.other_param, self._dlg.pool)
_dict_to_pjsip_param(from_header_parameters, &self._dlg.local.info.other_param, self._dlg.pool)
_dict_to_pjsip_param(to_header_parameters, &self._dlg.remote.info.other_param, self._dlg.pool)
self.from_header = FrozenFromHeader_create(self._dlg.local.info)
self.to_header = FrozenToHeader.new(to_header)
self.refer_to_header = FrozenReferToHeader.new(refer_to_header)
with nogil:
status = pjsip_evsub_create_uac(self._dlg, &_refer_cb, &_refer_event.pj_str, PJSIP_EVSUB_NO_EVENT_ID, &self._obj)
if status != 0:
raise PJSIPError("Could not create REFER", status)
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, <void *> self)
_BaseRouteHeader_to_pjsip_route_hdr(self.route_header, &self._route_header, self._dlg.pool)
pj_list_init(<pj_list *> &self._route_set)
pj_list_insert_after(<pj_list *> &self._route_set, <pj_list *> &self._route_header)
with nogil:
status = pjsip_dlg_set_route_set(self._dlg, <pjsip_route_hdr *> &self._route_set)
if status != 0:
raise PJSIPError("Could not set route on REFER", status)
if self.credentials is not None:
cred_info = self.credentials.get_cred_info()
with nogil:
status = pjsip_auth_clt_set_credentials(&self._dlg.auth_sess, 1, cred_info)
if status != 0:
raise PJSIPError("Could not set credentials for REFER", status)
def __dealloc__(self):
cdef PJSIPUA ua = self._get_ua()
if ua is not None:
self._cancel_timers(ua, 1, 1)
if self._obj != NULL:
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, NULL)
with nogil:
pjsip_evsub_terminate(self._obj, 0)
self._obj = NULL
if self._dlg != NULL:
with nogil:
pjsip_dlg_dec_session(self._dlg, &ua._module)
self._dlg = NULL
def send_refer(self, int create_subscription=1, list extra_headers not None=list(), object timeout=None):
cdef PJSIPUA ua = self._get_ua()
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
if self.state != "NULL":
raise SIPCoreError('This method may only be called in the "NULL" state')
if timeout is not None:
if timeout <= 0:
raise ValueError("Timeout value cannot be negative")
self._request_timeout.sec = int(timeout)
self._request_timeout.msec = (timeout * 1000) % 1000
else:
self._request_timeout.sec = 0
self._request_timeout.msec = 0
if extra_headers is not None:
self.extra_headers = frozenlist([header.frozen_type.new(header) for header in extra_headers])
self._create_subscription = create_subscription
self._send_refer(ua, &self._request_timeout, self.refer_to_header, self.extra_headers)
_add_event("SIPReferralWillStart", dict(obj=self))
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
def refresh(self, ContactHeader contact_header=None, list extra_headers not None=list(), object timeout=None):
cdef PJSIPUA ua = self._get_ua()
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
if self.state not in ("ACCEPTED", "ACTIVE", "PENDING"):
raise SIPCoreError('This method may only be called in the "ACCEPTED", "ACTIVE" or "PENDING" states')
if timeout is not None:
if timeout <= 0:
raise ValueError("Timeout value cannot be negative")
self._request_timeout.sec = int(timeout)
self._request_timeout.msec = (timeout * 1000) % 1000
else:
self._request_timeout.sec = 0
self._request_timeout.msec = 0
if contact_header is not None:
self._update_contact_header(contact_header)
if extra_headers is not None:
self.extra_headers = frozenlist([header.frozen_type.new(header) for header in extra_headers])
self._send_subscribe(ua, 600, &self._request_timeout, self.extra_headers)
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
def end(self, object timeout=None):
cdef pj_time_val end_timeout
cdef PJSIPUA ua = self._get_ua()
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
if self.state == "TERMINATED":
return
if self.state == "NULL":
raise SIPCoreError('This method may not be called in the "NULL" state')
if timeout is not None:
if timeout <= 0:
raise ValueError("Timeout value cannot be negative")
end_timeout.sec = int(timeout)
end_timeout.msec = (timeout * 1000) % 1000
else:
end_timeout.sec = 0
end_timeout.msec = 0
self._want_end = 1
self._cancel_timers(ua, 1, 1)
_add_event("SIPReferralWillEnd", dict(obj=self))
try:
self._send_subscribe(ua, 0, &end_timeout, frozenlist([]))
except PJSIPError, e:
self._term_reason = e.args[0]
if self._obj != NULL:
pjsip_evsub_terminate(self._obj, 1)
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
cdef PJSIPUA _get_ua(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
self._obj = NULL
self._timeout_timer_active = 0
self._refresh_timer_active = 0
self.state = "TERMINATED"
return None
else:
return ua
cdef int _update_contact_header(self, BaseContactHeader contact_header) except -1:
# The PJSIP functions called here don't do much, so there is no need to call them
# without the gil.
cdef pj_str_t contact_str_pj
cdef pjsip_uri *contact
contact_str = str(contact_header.uri)
if contact_header.display_name:
- contact_str = "%s <%s>" % (contact_header.display_name.encode('utf-8'), contact_str)
- pj_strdup2_with_null(self._dlg.pool, &contact_str_pj, contact_str)
+ contact_str = "%s <%s>" % (contact_header.display_name, contact_str)
+ pj_strdup2_with_null(self._dlg.pool, &contact_str_pj, contact_str.encode())
contact = pjsip_parse_uri(self._dlg.pool, contact_str_pj.ptr, contact_str_pj.slen, PJSIP_PARSE_URI_AS_NAMEADDR)
if contact == NULL:
raise SIPCoreError("Not a valid Contact header: %s" % contact_str)
self._dlg.local.contact = pjsip_contact_hdr_create(self._dlg.pool)
self._dlg.local.contact.uri = contact
if contact_header.expires is not None:
self._dlg.local.contact.expires = contact_header.expires
if contact_header.q is not None:
self._dlg.local.contact.q1000 = int(contact_header.q*1000)
parameters = contact_header.parameters.copy()
parameters.pop("q", None)
parameters.pop("expires", None)
_dict_to_pjsip_param(parameters, &self._dlg.local.contact.other_param, self._dlg.pool)
self.local_contact_header = FrozenContactHeader.new(contact_header)
return 0
cdef int _cancel_timers(self, PJSIPUA ua, int cancel_timeout, int cancel_refresh) except -1:
if cancel_timeout and self._timeout_timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timeout_timer)
self._timeout_timer_active = 0
if cancel_refresh and self._refresh_timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._refresh_timer)
self._refresh_timer_active = 0
cdef int _send_refer(self, PJSIPUA ua, pj_time_val *timeout, FrozenReferToHeader refer_to_header, frozenlist extra_headers) except -1:
global _refer_method
cdef pjsip_method refer_method
cdef pjsip_tx_data *tdata
cdef int status
pjsip_method_init_np(&refer_method, &_refer_method.pj_str)
with nogil:
status = pjsip_evsub_initiate(self._obj, &refer_method, -1, &tdata)
if status != 0:
raise PJSIPError("Could not create REFER message", status)
_add_headers_to_tdata(tdata, [refer_to_header, Header('Referred-By', str(self.from_header.uri))])
_add_headers_to_tdata(tdata, extra_headers)
if not self._create_subscription:
_add_headers_to_tdata(tdata, [Header('Refer-Sub', 'false')])
# We can't remove the Event header or PJSIP will fail to match responses to this request
_remove_headers_from_tdata(tdata, ["Expires"])
with nogil:
status = pjsip_evsub_send_request(self._obj, tdata)
if status != 0:
raise PJSIPError("Could not send REFER message", status)
if timeout.sec or timeout.msec:
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timeout_timer, timeout)
if status == 0:
self._timeout_timer_active = 1
cdef int _send_subscribe(self, PJSIPUA ua, int expires, pj_time_val *timeout, frozenlist extra_headers) except -1:
cdef pjsip_tx_data *tdata
cdef int status
with nogil:
status = pjsip_evsub_initiate(self._obj, NULL, expires, &tdata)
if status != 0:
raise PJSIPError("Could not create SUBSCRIBE message", status)
_add_headers_to_tdata(tdata, extra_headers)
with nogil:
status = pjsip_evsub_send_request(self._obj, tdata)
if status != 0:
raise PJSIPError("Could not send SUBSCRIBE message", status)
self._cancel_timers(ua, 1, 0)
if timeout.sec or timeout.msec:
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timeout_timer, timeout)
if status == 0:
self._timeout_timer_active = 1
cdef int _cb_state(self, PJSIPUA ua, object state, int code, str reason) except -1:
# PJSIP holds the dialog lock when this callback is entered
cdef object prev_state = self.state
cdef int status
self.state = state
if state == "ACCEPTED" and prev_state == "SENT":
_add_event("SIPReferralDidStart", dict(obj=self))
if not self._create_subscription:
# Terminate the subscription
self._want_end = 1
_add_event("SIPReferralWillEnd", dict(obj=self))
with nogil:
pjsip_evsub_terminate(self._obj, 1)
elif state == "TERMINATED":
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, NULL)
self._cancel_timers(ua, 1, 1)
self._obj = NULL
if self._want_end:
_add_event("SIPReferralDidEnd", dict(obj=self))
else:
if self._term_reason is not None:
_add_event("SIPReferralDidFail", dict(obj=self, code=self._term_code, reason=self._term_reason))
elif code/100 == 2:
_add_event("SIPReferralDidEnd", dict(obj=self))
else:
_add_event("SIPReferralDidFail", dict(obj=self, code=code, reason=reason))
if prev_state != state:
_add_event("SIPReferralChangedState", dict(obj=self, prev_state=prev_state, state=state))
cdef int _cb_got_response(self, PJSIPUA ua, pjsip_rx_data *rdata, str method) except -1:
# PJSIP holds the dialog lock when this callback is entered
global _refer_sub_hdr_name
cdef int expires
cdef int status
cdef dict event_dict = dict()
cdef pj_time_val refresh
cdef pjsip_generic_int_hdr *expires_hdr
cdef pjsip_generic_string_hdr *refer_sub_header
self.to_header = FrozenToHeader_create(rdata.msg_info.to_hdr)
if self.state != "TERMINATED" and not self._want_end:
self._cancel_timers(ua, 1, 0)
if method == "REFER":
refer_sub_header = <pjsip_generic_string_hdr *> pjsip_msg_find_hdr_by_name(rdata.msg_info.msg, &_refer_sub_hdr_name.pj_str, NULL);
if not self._create_subscription:
if not (refer_sub_header != NULL and _pj_str_to_str(refer_sub_header.hvalue) == "false"):
self._create_subscription = 1
elif method == "SUBSCRIBE":
# For the REFER method the expires value will be taken from the NOTIFY Subscription-State header
expires_hdr = <pjsip_generic_int_hdr *> pjsip_msg_find_hdr(rdata.msg_info.msg, PJSIP_H_EXPIRES, NULL)
if expires_hdr != NULL and not self._refresh_timer_active:
expires = expires_hdr.ivalue
refresh.sec = max(1, expires - self.expire_warning_time, expires/2)
refresh.msec = 0
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._refresh_timer, &refresh)
if status == 0:
self._refresh_timer_active = 1
if self.state != "TERMINATED":
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
try:
self.remote_contact_header = event_dict['headers']['Contact'][0]
except LookupError:
pass
cdef int _cb_notify(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
# PJSIP holds the dialog lock when this callback is entered
global _subscription_state_hdr_name
cdef pjsip_sub_state_hdr *sub_state_hdr
cdef pj_time_val refresh
cdef int expires
cdef dict event_dict = dict()
cdef dict notify_dict = dict(obj=self)
sub_state_hdr = <pjsip_sub_state_hdr *> pjsip_msg_find_hdr_by_name(rdata.msg_info.msg, &_subscription_state_hdr_name.pj_str, NULL)
if self.state != "TERMINATED" and sub_state_hdr != NULL and sub_state_hdr.expires_param > 0 and not self._refresh_timer_active:
expires = sub_state_hdr.expires_param
refresh.sec = max(1, expires - self.expire_warning_time, expires/2)
refresh.msec = 0
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._refresh_timer, &refresh)
if status == 0:
self._refresh_timer_active = 1
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
if self.state != "TERMINATED":
try:
self.remote_contact_header = event_dict['headers']['Contact'][0]
except LookupError:
pass
notify_dict["request_uri"] = event_dict["request_uri"]
notify_dict["from_header"] = event_dict["headers"].get("From", None)
notify_dict["to_header"] = event_dict["headers"].get("To", None)
notify_dict["headers"] = event_dict["headers"]
notify_dict["body"] = event_dict["body"]
content_type = notify_dict["headers"].get("Content-Type", None)
notify_dict["content_type"] = content_type.content_type if content_type else None
event = notify_dict["headers"].get("Event", None)
notify_dict["event"] = event.event if event else None
_add_event("SIPReferralGotNotify", notify_dict)
cdef int _cb_timeout_timer(self, PJSIPUA ua):
# Timer callback, dialog lock is not held by PJSIP
global sip_status_messages
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
self._term_code = PJSIP_SC_TSX_TIMEOUT
self._term_reason = sip_status_messages[PJSIP_SC_TSX_TIMEOUT]
if self._obj != NULL:
with nogil:
pjsip_evsub_terminate(self._obj, 1)
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
cdef int _cb_refresh_timer(self, PJSIPUA ua):
# Timer callback, dialog lock is not held by PJSIP
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
self._send_subscribe(ua, 600, &self._request_timeout, self.extra_headers)
except PJSIPError, e:
self._term_reason = e.args[0]
if self._obj != NULL:
with nogil:
pjsip_evsub_terminate(self._obj, 1)
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
cdef class IncomingReferral:
def __cinit__(self):
self.state = None
self.peer_address = None
self._create_subscription = 1
self.local_contact_header = None
self.remote_contact_header = None
def __dealloc__(self):
cdef PJSIPUA ua = self._get_ua(0)
self._initial_response = NULL
self._initial_tsx = NULL
if self._obj != NULL:
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, NULL)
with nogil:
pjsip_evsub_terminate(self._obj, 0)
self._obj = NULL
if self._dlg != NULL and ua is not None:
with nogil:
pjsip_dlg_dec_session(self._dlg, &ua._module)
self._dlg = NULL
cdef int init(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
global _incoming_refer_subs_cb
global _event_hdr_name
global _refer_event
global _refer_to_hdr_name
global _refer_sub_hdr_name
cdef int status
cdef str transport
cdef FrozenSIPURI request_uri
cdef FrozenContactHeader contact_header
cdef PJSTR contact_str
cdef dict event_dict
cdef pjsip_generic_string_hdr *refer_to_header
cdef pjsip_generic_string_hdr *refer_sub_header
cdef pjsip_tpselector tp_sel
cdef pjsip_event_hdr *event_header
refer_to_header = <pjsip_generic_string_hdr *> pjsip_msg_find_hdr_by_name(rdata.msg_info.msg, &_refer_to_hdr_name.pj_str, NULL);
if refer_to_header == NULL:
with nogil:
status = pjsip_endpt_create_response(ua._pjsip_endpoint._obj, rdata, 400, NULL, &self._initial_response)
if status != 0:
raise PJSIPError("Could not create response", status)
with nogil:
status = pjsip_endpt_send_response2(ua._pjsip_endpoint._obj, rdata, self._initial_response, NULL, NULL)
if status != 0:
with nogil:
pjsip_tx_data_dec_ref(self._initial_response)
raise PJSIPError("Could not send response", status)
return 0
# If there is a Ref-Sub header and it contains 'false', don't establish a subscription
refer_sub_header = <pjsip_generic_string_hdr *> pjsip_msg_find_hdr_by_name(rdata.msg_info.msg, &_refer_sub_hdr_name.pj_str, NULL);
if refer_sub_header != NULL and _pj_str_to_str(refer_sub_header.hvalue) == "false":
self._create_subscription = 0
self._set_state("incoming")
self.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
event_dict = dict(obj=self, prev_state=self.state, state="incoming")
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
try:
self.remote_contact_header = event_dict['headers']['Contact'][0]
except LookupError:
# Contact header is required
with nogil:
status = pjsip_endpt_create_response(ua._pjsip_endpoint._obj, rdata, 400, NULL, &self._initial_response)
if status != 0:
raise PJSIPError("Could not create response", status)
with nogil:
status = pjsip_endpt_send_response2(ua._pjsip_endpoint._obj, rdata, self._initial_response, NULL, NULL)
if status != 0:
with nogil:
pjsip_tx_data_dec_ref(self._initial_response)
raise PJSIPError("Could not send response", status)
return 0
event_dict["refer_to"] = event_dict["headers"].get("Refer-To")
transport = rdata.tp_info.transport.type_name.lower()
request_uri = event_dict["request_uri"]
if _is_valid_ip(pj_AF_INET(), request_uri.host):
self.local_contact_header = FrozenContactHeader(request_uri)
else:
self.local_contact_header = FrozenContactHeader(FrozenSIPURI(host=_pj_str_to_str(rdata.tp_info.transport.local_name.host),
user=request_uri.user, port=rdata.tp_info.transport.local_name.port,
parameters=(frozendict(transport=transport) if transport != "udp" else frozendict())))
contact_str = PJSTR(self.local_contact_header.body)
with nogil:
status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata, &contact_str.pj_str, &self._dlg)
if status != 0:
with nogil:
status = pjsip_endpt_create_response(ua._pjsip_endpoint._obj, rdata, 400, NULL, &self._initial_response)
if status != 0:
raise PJSIPError("Could not create response", status)
with nogil:
status = pjsip_endpt_send_response2(ua._pjsip_endpoint._obj, rdata, self._initial_response, NULL, NULL)
if status != 0:
with nogil:
pjsip_tx_data_dec_ref(self._initial_response)
raise PJSIPError("Could not send response", status)
return 0
# Increment dialog session count so that it's never destroyed by PJSIP
with nogil:
status = pjsip_dlg_inc_session(self._dlg, &ua._module)
if status != 0:
pjsip_dlg_dec_lock(self._dlg)
raise PJSIPError("Could not increment dialog session count", status)
# PJSIP event framework needs an Event header, even if it's not needed for REFER, so we insert a fake one
event_header = <pjsip_event_hdr *> pjsip_msg_find_hdr_by_name(rdata.msg_info.msg, &_event_hdr_name.pj_str, NULL)
if event_header == NULL:
event_header = pjsip_event_hdr_create(rdata.tp_info.pool)
event_header.event_type = _refer_event.pj_str
pjsip_msg_add_hdr(rdata.msg_info.msg, <pjsip_hdr *> event_header)
self._initial_tsx = pjsip_rdata_get_tsx(rdata)
with nogil:
status = pjsip_evsub_create_uas(self._dlg, &_incoming_refer_subs_cb, rdata, 0, &self._obj)
pjsip_dlg_dec_lock(self._dlg)
if status != 0:
with nogil:
pjsip_tsx_terminate(self._initial_tsx, 500)
self._initial_tsx = NULL
self._dlg = NULL
raise PJSIPError("Could not create incoming REFER session", status)
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, <void *> self)
with nogil:
status = pjsip_dlg_create_response(self._dlg, rdata, 500, NULL, &self._initial_response)
if status != 0:
with nogil:
pjsip_tsx_terminate(self._initial_tsx, 500)
self._initial_tsx = NULL
raise PJSIPError("Could not create response for incoming REFER", status)
_add_event("SIPIncomingReferralGotRefer", event_dict)
return 0
def accept(self, int code=202, int duration=180):
cdef PJSIPUA ua = self._get_ua(1)
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
if self.state != "incoming":
raise SIPCoreInvalidStateError('Can only accept an incoming REFER in the "incoming" state, '+
'object is currently in the "%s" state' % self.state)
pjsip_evsub_update_expires(self._obj, duration)
self._send_initial_response(code)
self._set_state("active")
if not self._create_subscription:
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, NULL)
with nogil:
pjsip_evsub_terminate(self._obj, 0)
self._obj = NULL
self._set_state("terminated")
_add_event("SIPIncomingReferralDidEnd", dict(obj=self))
else:
self._set_content(100, "Trying")
self._send_notify()
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
def reject(self, int code):
cdef PJSIPUA ua = self._get_ua(1)
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
if self.state != "incoming":
raise SIPCoreInvalidStateError('Can only reject an incoming REFER in the "incoming" state, '+
'object is currently in the "%s" state' % self.state)
if not (300 <= code < 700):
raise ValueError("Invalid negative SIP response code: %d" % code)
self._send_initial_response(code)
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, NULL)
with nogil:
pjsip_evsub_terminate(self._obj, 0)
self._obj = NULL
self._set_state("terminated")
_add_event("SIPIncomingReferralDidEnd", dict(obj=self))
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
def send_notify(self, int code, str status=None):
cdef PJSIPUA ua = self._get_ua(1)
cdef str content
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
if self.state != "active":
raise SIPCoreInvalidStateError('Can only send NOTIFY for a REFER session in the "active" state, '
'object is currently in the "%s" state' % self.state)
self._set_content(code, status)
self._send_notify()
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
def end(self, int code, str status=None):
cdef PJSIPUA ua = self._get_ua(0)
with nogil:
pjsip_dlg_inc_lock(self._dlg)
try:
if self.state == "terminated":
return
if self.state not in ("pending", "active"):
raise SIPCoreInvalidStateError('Can only end an incoming REFER session in the "pending" or '+
'"active" state, object is currently in the "%s" state' % self.state)
self._set_content(code, status)
self._terminate(ua, 1)
finally:
with nogil:
pjsip_dlg_dec_lock(self._dlg)
cdef PJSIPUA _get_ua(self, int raise_exception):
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
self._obj = NULL
self._set_state("terminated")
if raise_exception:
raise
else:
return None
else:
return ua
cdef int _set_content(self, int code, str reason) except -1:
cdef str content
if reason is None:
try:
reason = sip_status_messages[code]
except IndexError:
reason = "Unknown"
content = "SIP/2.0 %d %s\r\n" % (code, reason)
self._content = PJSTR(content)
cdef int _set_state(self, str state) except -1:
cdef str prev_state
prev_state = self.state
self.state = state
if prev_state != state and prev_state is not None:
_add_event("SIPIncomingReferralChangedState", dict(obj=self, prev_state=prev_state, state=state))
cdef int _send_initial_response(self, int code) except -1:
cdef int status
with nogil:
status = pjsip_dlg_modify_response(self._dlg, self._initial_response, code, NULL)
if status != 0:
raise PJSIPError("Could not modify response", status)
# pjsip_dlg_modify_response() increases ref count unncessarily
with nogil:
pjsip_tx_data_dec_ref(self._initial_response)
if not self._create_subscription:
_add_headers_to_tdata(self._initial_response, [Header('Refer-Sub', 'false')])
with nogil:
status = pjsip_dlg_send_response(self._dlg, self._initial_tsx, self._initial_response)
if status != 0:
raise PJSIPError("Could not send response", status)
self._initial_response = NULL
self._initial_tsx = NULL
cdef int _send_notify(self) except -1:
cdef pjsip_evsub_state state
cdef pj_str_t *reason_p
cdef pjsip_tx_data *tdata
cdef int status
cdef dict _sipfrag_version = dict(version="2.0")
cdef PJSTR _content_type = PJSTR(b"message")
cdef PJSTR _content_subtype = PJSTR(b"sipfrag")
cdef PJSTR reason = PJSTR(b"noresource")
reason_p = NULL
if self.state == "pending":
state = PJSIP_EVSUB_STATE_PENDING
elif self.state == "active":
state = PJSIP_EVSUB_STATE_ACTIVE
else:
state = PJSIP_EVSUB_STATE_TERMINATED
reason_p = &reason.pj_str
with nogil:
status = pjsip_evsub_notify(self._obj, state, NULL, reason_p, &tdata)
if status != 0:
raise PJSIPError("Could not create NOTIFY request", status)
if self.state in ("active", "terminated"):
tdata.msg.body = pjsip_msg_body_create(tdata.pool, &_content_type.pj_str, &_content_subtype.pj_str, &self._content.pj_str)
_dict_to_pjsip_param(_sipfrag_version, &tdata.msg.body.content_type.param, tdata.pool)
with nogil:
status = pjsip_evsub_send_request(self._obj, tdata)
if status != 0:
raise PJSIPError("Could not send NOTIFY request", status)
event_dict = dict(obj=self)
_pjsip_msg_to_dict(tdata.msg, event_dict)
_add_event("SIPIncomingReferralSentNotify", event_dict)
return 0
cdef int _terminate(self, PJSIPUA ua, int do_cleanup) except -1:
cdef int status
self._set_state("terminated")
self._send_notify()
if do_cleanup:
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, NULL)
self._obj = NULL
_add_event("SIPIncomingReferralDidEnd", dict(obj=self))
cdef int _cb_rx_refresh(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
# PJSIP holds the dialog lock when this callback is entered
cdef int status
cdef pjsip_expires_hdr *expires_header
cdef int expires
cdef dict event_dict
event_dict = dict(obj=self)
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
expires_header = <pjsip_expires_hdr *> pjsip_msg_find_hdr(rdata.msg_info.msg, PJSIP_H_EXPIRES, NULL)
if expires_header == NULL:
self._expires_time.sec = 600
self._expires_time.msec = 0
else:
if expires_header.ivalue == 0:
_add_event("SIPIncomingReferralGotUnsubscribe", event_dict)
# cleanup will be done by _cb_tsx
self._terminate(ua, 0)
return 200
else:
expires = min(expires_header.ivalue, 600)
self._expires_time.sec = expires
self._expires_time.msec = 0
_add_event("SIPIncomingReferralGotRefreshingSubscribe", event_dict)
# Last NOTIFY will be resent
self._send_notify()
if self.state == "active":
return 200
else:
return 202
cdef int _cb_server_timeout(self, PJSIPUA ua) except -1:
# PJSIP holds the dialog lock when this callback is entered
self._terminate(ua, 1)
cdef int _cb_tsx(self, PJSIPUA ua, pjsip_event *event) except -1:
# PJSIP holds the dialog lock when this callback is entered
cdef pjsip_rx_data *rdata
cdef dict event_dict
cdef int status_code
if (event != NULL and event.type == PJSIP_EVENT_TSX_STATE and
event.body.tsx_state.tsx.role == PJSIP_ROLE_UAC and
_pj_str_to_str(event.body.tsx_state.tsx.method.name) == "NOTIFY" and
event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_COMPLETED):
event_dict = dict(obj=self)
rdata = event.body.tsx_state.src.rdata
if rdata != NULL:
if self.peer_address is None:
self.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
self.peer_address.ip = rdata.pkt_info.src_name
self.peer_address.port = rdata.pkt_info.src_port
status_code = event.body.tsx_state.tsx.status_code
if event.body.tsx_state.type==PJSIP_EVENT_RX_MSG and status_code/100==2:
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
try:
self.remote_contact_header = event_dict['headers']['Contact'][0]
except LookupError:
pass
_add_event("SIPIncomingReferralNotifyDidSucceed", event_dict)
else:
if event.body.tsx_state.type == PJSIP_EVENT_RX_MSG:
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
else:
event_dict["code"] = status_code
event_dict["reason"] = _pj_str_to_str(event.body.tsx_state.tsx.status_text)
_add_event("SIPIncomingReferralNotifyDidFail", event_dict)
if status_code in (408, 481) or status_code/100==7:
# PJSIP will terminate the subscription and the dialog will be destroyed
self._terminate(ua, 1)
elif (event != NULL and event.type == PJSIP_EVENT_TSX_STATE and
event.body.tsx_state.tsx.role == PJSIP_ROLE_UAC and
_pj_str_to_str(event.body.tsx_state.tsx.method.name) == "NOTIFY" and
event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_TERMINATED):
event_dict = dict(obj=self)
status_code = event.body.tsx_state.tsx.status_code
if status_code == 408:
# Local timeout, PJSIP will terminate the subscription and the dialog will be destroyed
event_dict["code"] = status_code
event_dict["reason"] = _pj_str_to_str(event.body.tsx_state.tsx.status_text)
_add_event("SIPIncomingReferralNotifyDidFail", event_dict)
self._terminate(ua, 1)
elif (event != NULL and event.type == PJSIP_EVENT_TSX_STATE and
event.body.tsx_state.tsx.role == PJSIP_ROLE_UAS and
_pj_str_to_str(event.body.tsx_state.tsx.method.name) == "REFER" and
event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_COMPLETED and
event.body.tsx_state.type == PJSIP_EVENT_TX_MSG):
event_dict = dict(obj=self)
_pjsip_msg_to_dict(event.body.tsx_state.src.tdata.msg, event_dict)
_add_event("SIPIncomingReferralAnsweredRefer", event_dict)
if self.state == "terminated" and self._obj != NULL:
pjsip_evsub_set_mod_data(self._obj, ua._event_module.id, NULL)
self._obj = NULL
cdef void _Referral_cb_state(pjsip_evsub *sub, pjsip_event *event) with gil:
cdef void *referral_void
cdef Referral referral
cdef object state
cdef int code = 0
cdef dict event_dict = dict()
cdef str reason = None
cdef pjsip_rx_data *rdata = NULL
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
referral_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if referral_void == NULL:
return
referral = <object> referral_void
state = pjsip_evsub_get_state_name(sub)
if (event != NULL and event.type == PJSIP_EVENT_TSX_STATE and
(event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_COMPLETED or
event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_TERMINATED)):
if state == "TERMINATED":
if event.body.tsx_state.tsx.role == PJSIP_ROLE_UAC:
code = event.body.tsx_state.tsx.status_code
reason = _pj_str_to_str(event.body.tsx_state.tsx.status_text)
else:
reason = "Referral has expired"
if event.body.tsx_state.type == PJSIP_EVENT_RX_MSG and _pj_str_to_str(event.body.tsx_state.tsx.method.name) == "NOTIFY":
# Extract code and reason from the sipfrag payload
rdata = event.body.tsx_state.src.rdata
if rdata != NULL:
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
if event_dict.get('body', None) is not None:
match = sipfrag_re.match(event_dict['body'])
if match:
code = int(match.group('code'))
reason = match.group('reason')
referral._cb_state(ua, state, code, reason)
except:
ua._handle_exception(1)
cdef void _Referral_cb_tsx(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) with gil:
cdef void *referral_void
cdef Referral referral
cdef pjsip_rx_data *rdata
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
referral_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if referral_void == NULL:
return
referral = <object> referral_void
if (event != NULL and event.type == PJSIP_EVENT_TSX_STATE and
event.body.tsx_state.type == PJSIP_EVENT_RX_MSG and
event.body.tsx_state.tsx.role == PJSIP_ROLE_UAC and
event.body.tsx_state.tsx.state == PJSIP_TSX_STATE_COMPLETED and
_pj_str_to_str(event.body.tsx_state.tsx.method.name) in ("REFER", "SUBSCRIBE") and
event.body.tsx_state.tsx.status_code/100 == 2):
rdata = event.body.tsx_state.src.rdata
if rdata != NULL:
if referral.peer_address is None:
referral.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
referral.peer_address.ip = rdata.pkt_info.src_name
referral.peer_address.port = rdata.pkt_info.src_port
referral._cb_got_response(ua, rdata, _pj_str_to_bytes(event.body.tsx_state.tsx.method.name))
except:
ua._handle_exception(1)
cdef void _Referral_cb_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil:
cdef void *referral_void
cdef Referral referral
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
referral_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if referral_void == NULL:
return
referral = <object> referral_void
if rdata != NULL:
if referral.peer_address is None:
referral.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
referral.peer_address.ip = rdata.pkt_info.src_name
referral.peer_address.port = rdata.pkt_info.src_port
referral._cb_notify(ua, rdata)
except:
ua._handle_exception(1)
cdef void _Referral_cb_refresh(pjsip_evsub *sub) with gil:
# We want to handle the refresh timer oursevles, ignore the PJSIP provided timer
pass
cdef void _Referral_cb_timer(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) with gil:
cdef Referral referral
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
if entry.user_data != NULL:
referral = <object> entry.user_data
if entry.id == 1:
referral._refresh_timer_active = 0
referral._cb_refresh_timer(ua)
else:
referral._timeout_timer_active = 0
referral._cb_timeout_timer(ua)
except:
ua._handle_exception(1)
cdef void _IncomingReferral_cb_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) with gil:
cdef void *referral_void
cdef IncomingReferral referral
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
referral_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if referral_void == NULL:
p_st_code[0] = 481
return
referral = <object> referral_void
if rdata != NULL:
if referral.peer_address is None:
referral.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
referral.peer_address.ip = rdata.pkt_info.src_name
referral.peer_address.port = rdata.pkt_info.src_port
p_st_code[0] = referral._cb_rx_refresh(ua, rdata)
except:
ua._handle_exception(1)
cdef void _IncomingReferral_cb_server_timeout(pjsip_evsub *sub) with gil:
cdef void *referral_void
cdef IncomingReferral referral
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
referral_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if referral_void == NULL:
return
referral = <object> referral_void
referral._cb_server_timeout(ua)
except:
ua._handle_exception(1)
cdef void _IncomingReferral_cb_tsx(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) with gil:
cdef void *referral_void
cdef IncomingReferral referral
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
referral_void = pjsip_evsub_get_mod_data(sub, ua._event_module.id)
if referral_void == NULL:
return
referral = <object> referral_void
referral._cb_tsx(ua, event)
except:
ua._handle_exception(1)
# Globals
#
cdef pjsip_evsub_user _refer_cb
_refer_cb.on_evsub_state = _Referral_cb_state
_refer_cb.on_tsx_state = _Referral_cb_tsx
_refer_cb.on_rx_notify = _Referral_cb_notify
_refer_cb.on_client_refresh = _Referral_cb_refresh
cdef pjsip_evsub_user _incoming_refer_subs_cb
_incoming_refer_subs_cb.on_rx_refresh = _IncomingReferral_cb_rx_refresh
_incoming_refer_subs_cb.on_server_timeout = _IncomingReferral_cb_server_timeout
_incoming_refer_subs_cb.on_tsx_state = _IncomingReferral_cb_tsx
sipfrag_re = re.compile(r'^SIP/2\.0\s+(?P<code>\d{3})\s+(?P<reason>[ a-zA-Z0-9_-]+)')
cdef PJSTR _refer_method = PJSTR(b"REFER")
cdef PJSTR _refer_event = PJSTR(b"refer")
cdef PJSTR _refer_to_hdr_name = PJSTR(b"Refer-To")
cdef PJSTR _refer_sub_hdr_name = PJSTR(b"Refer-Sub")
cdef PJSTR _subscription_state_hdr_name = PJSTR(b"Subscription-State")
diff --git a/sipsimple/core/_core.request.pxi b/sipsimple/core/_core.request.pxi
index 80aa5c9b..67246c7a 100644
--- a/sipsimple/core/_core.request.pxi
+++ b/sipsimple/core/_core.request.pxi
@@ -1,507 +1,506 @@
from datetime import datetime, timedelta
cdef class EndpointAddress:
def __init__(self, ip, port):
self.ip = ip
self.port = port
def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, self.ip, self.port)
def __str__(self):
return "%s:%d" % (self.ip, self.port)
cdef class Request:
expire_warning_time = 30
# properties
property method:
def __get__(self):
return self._method.str
property call_id:
def __get__(self):
return self._call_id.str
property content_type:
def __get__(self):
if self._content_type is None:
return None
else:
return "/".join([self._content_type.str, self._content_subtype.str])
property body:
def __get__(self):
if self._body is None:
return None
else:
return self._body.str
property expires_in:
def __get__(self):
cdef object dt
self._get_ua()
if self.state != "EXPIRING" or self._expire_time is None:
return 0
else:
dt = self._expire_time - datetime.now()
return max(0, dt.seconds)
# public methods
def __cinit__(self, *args, **kwargs):
self.state = "INIT"
self.peer_address = None
pj_timer_entry_init(&self._timer, 0, <void *> self, _Request_cb_timer)
self._timer_active = 0
def __init__(self, method, SIPURI request_uri not None, FromHeader from_header not None, ToHeader to_header not None,
RouteHeader route_header not None, Credentials credentials=None, ContactHeader contact_header=None, call_id=None, cseq=None,
object extra_headers=None, content_type=None, body=None):
cdef pjsip_method method_pj
cdef PJSTR from_header_str
cdef PJSTR to_header_str
cdef PJSTR request_uri_str
cdef PJSTR contact_header_str
cdef pj_str_t *contact_header_pj = NULL
cdef pj_str_t *call_id_pj = NULL
cdef object content_type_spl
cdef pjsip_hdr *hdr
cdef pjsip_contact_hdr *contact_hdr
cdef pjsip_cid_hdr *cid_hdr
cdef pjsip_cseq_hdr *cseq_hdr
cdef int status
cdef dict event_dict
cdef PJSIPUA ua = _get_ua()
if self._tsx != NULL or self.state != "INIT":
raise SIPCoreError("Request.__init__() was already called")
if cseq is not None and cseq < 0:
raise ValueError("cseq argument cannot be negative")
if extra_headers is not None:
header_names = set([header.name for header in extra_headers])
if "Route" in header_names:
raise ValueError("Route should be specified with route_header argument, not extra_headers")
if "Content-Type" in header_names:
raise ValueError("Content-Type should be specified with content_type argument, not extra_headers")
else:
header_names = ()
if content_type is not None and body is None:
raise ValueError("Cannot specify a content_type without a body")
if content_type is None and body is not None:
raise ValueError("Cannot specify a body without a content_type")
self._method = PJSTR(method.encode())
pjsip_method_init_np(&method_pj, &self._method.pj_str)
if credentials is not None:
self.credentials = FrozenCredentials.new(credentials)
from_header_str = PJSTR(from_header.body.encode())
self.to_header = FrozenToHeader.new(to_header)
to_header_str = PJSTR(to_header.body.encode())
struri = str(request_uri)
self.request_uri = FrozenSIPURI.new(request_uri)
request_uri_str = PJSTR(struri.encode())
self.route_header = FrozenRouteHeader.new(route_header)
#self.route_header = FrozenRouteHeader(FrozenSIPURI(host=route_header.uri.host))
self.route_header.uri.parameters.dict["lr"] = None # always send lr parameter in Route header
self.route_header.uri.parameters.dict["hide"] = None # always hide Route header
if contact_header is not None:
self.contact_header = FrozenContactHeader.new(contact_header)
contact_parameters = contact_header.parameters.copy()
contact_parameters.pop("q", None)
contact_parameters.pop("expires", None)
contact_header.parameters = {}
contact_header_str = PJSTR(contact_header.body.encode())
contact_header_pj = &contact_header_str.pj_str
if call_id is not None:
self._call_id = PJSTR(call_id.encode())
call_id_pj = &self._call_id.pj_str
if cseq is None:
self.cseq = -1
else:
self.cseq = cseq
if extra_headers is None:
self.extra_headers = frozenlist()
else:
self.extra_headers = frozenlist([header.frozen_type.new(header) for header in extra_headers])
if body is not None:
content_type_spl = content_type.split("/", 1)
self._content_type = PJSTR(content_type_spl[0].encode())
self._content_subtype = PJSTR(content_type_spl[1].encode())
self._body = PJSTR(body)
status = pjsip_endpt_create_request(ua._pjsip_endpoint._obj, &method_pj, &request_uri_str.pj_str,
&from_header_str.pj_str, &to_header_str.pj_str, contact_header_pj,
call_id_pj, self.cseq, NULL, &self._tdata)
if status != 0:
raise PJSIPError("Could not create request", status)
if body is not None:
self._tdata.msg.body = pjsip_msg_body_create(self._tdata.pool, &self._content_type.pj_str,
&self._content_subtype.pj_str, &self._body.pj_str)
status = _BaseRouteHeader_to_pjsip_route_hdr(self.route_header, &self._route_header, self._tdata.pool)
pjsip_msg_add_hdr(self._tdata.msg, <pjsip_hdr *> &self._route_header)
hdr = <pjsip_hdr *> (<pj_list *> &self._tdata.msg.hdr).next
while hdr != &self._tdata.msg.hdr:
hdr_name = _pj_str_to_str(hdr.name)
if hdr_name in header_names:
raise ValueError("Cannot override %s header value in extra_headers" % _pj_str_to_bytes(hdr.name))
if hdr.type == PJSIP_H_CONTACT:
contact_hdr = <pjsip_contact_hdr *> hdr
_dict_to_pjsip_param(contact_parameters, &contact_hdr.other_param, self._tdata.pool)
elif hdr.type == PJSIP_H_CALL_ID:
cid_hdr = <pjsip_cid_hdr *> hdr
self._call_id = PJSTR(_pj_str_to_bytes(cid_hdr.id))
elif hdr.type == PJSIP_H_CSEQ:
cseq_hdr = <pjsip_cseq_hdr *> hdr
self.cseq = cseq_hdr.cseq
elif hdr.type == PJSIP_H_FROM:
self.from_header = FrozenFromHeader_create(<pjsip_fromto_hdr*> hdr)
else:
pass
hdr = <pjsip_hdr *> (<pj_list *> hdr).next
_add_headers_to_tdata(self._tdata, self.extra_headers)
event_dict = dict(obj=self)
_pjsip_msg_to_dict(self._tdata.msg, event_dict)
print('Request dict %s' % event_dict)
if self.credentials is not None:
status = pjsip_auth_clt_init(&self._auth, ua._pjsip_endpoint._obj, self._tdata.pool, 0)
if status != 0:
raise PJSIPError("Could not init authentication credentials", status)
status = pjsip_auth_clt_set_credentials(&self._auth, 1, self.credentials.get_cred_info())
if status != 0:
raise PJSIPError("Could not set authentication credentials", status)
self._need_auth = 1
else:
self._need_auth = 0
status = pjsip_tsx_create_uac(&ua._module, self._tdata, &self._tsx)
if status != 0:
raise PJSIPError("Could not create transaction for request", status)
self._tsx.mod_data[ua._module.id] = <void *> self
def __dealloc__(self):
cdef PJSIPUA ua = self._get_ua()
if self._tsx != NULL:
self._tsx.mod_data[ua._module.id] = NULL
if self._tsx.state < PJSIP_TSX_STATE_COMPLETED:
pjsip_tsx_terminate(self._tsx, 500)
self._tsx = NULL
if self._tdata != NULL:
pjsip_tx_data_dec_ref(self._tdata)
self._tdata = NULL
if self._timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
def send(self, timeout=None):
cdef pj_time_val timeout_pj
cdef int status
cdef PJSIPUA ua = self._get_ua()
if self.state != "INIT":
raise SIPCoreError('This method may only be called in the "INIT" state, current state is "%s"' % self.state)
if timeout is not None:
if timeout <= 0:
raise ValueError("Timeout value cannot be negative")
timeout_pj.sec = int(timeout)
timeout_pj.msec = (timeout * 1000) % 1000
self._timeout = timeout
status = pjsip_tsx_send_msg(self._tsx, self._tdata)
if status != 0:
raise PJSIPError("Could not send request", status)
pjsip_tx_data_add_ref(self._tdata)
if timeout:
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &timeout_pj)
if status == 0:
self._timer_active = 1
self.state = "IN_PROGRESS"
def end(self):
cdef PJSIPUA ua = self._get_ua()
if self.state == "IN_PROGRESS":
pjsip_tsx_terminate(self._tsx, 408)
elif self.state == "EXPIRING":
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
# private methods
cdef PJSIPUA _get_ua(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
self._tsx = NULL
self._tdata = NULL
self._timer_active = 0
self.state = "TERMINATED"
return None
else:
return ua
cdef int _cb_tsx_state(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
cdef pjsip_tx_data *tdata_auth
cdef pjsip_transaction *tsx_auth
cdef pjsip_cseq_hdr *cseq
cdef dict event_dict
cdef int expires = -1
cdef SIPURI contact_uri
cdef dict contact_params
cdef pj_time_val timeout_pj
cdef int status
if rdata != NULL:
self.to_header = FrozenToHeader_create(rdata.msg_info.to_hdr)
if self.peer_address is None:
self.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
self.peer_address.ip = rdata.pkt_info.src_name
self.peer_address.port = rdata.pkt_info.src_port
if self._tsx.state == PJSIP_TSX_STATE_PROCEEDING:
if rdata == NULL:
return 0
event_dict = dict(obj=self)
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
_add_event("SIPRequestGotProvisionalResponse", event_dict)
elif self._tsx.state == PJSIP_TSX_STATE_COMPLETED:
if self._timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
if self._need_auth and self._tsx.status_code in [401, 407]:
self._need_auth = 0
status = pjsip_auth_clt_reinit_req(&self._auth, rdata, self._tdata, &tdata_auth)
if status != 0:
_add_event("SIPRequestDidFail",
dict(obj=self, code=0,
reason="Could not add auth data to request %s" % _pj_status_to_str(status)))
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
return 0
cseq = <pjsip_cseq_hdr *> pjsip_msg_find_hdr(tdata_auth.msg, PJSIP_H_CSEQ, NULL)
if cseq != NULL:
cseq.cseq += 1
self.cseq = cseq.cseq
status = pjsip_tsx_create_uac(&ua._module, tdata_auth, &tsx_auth)
if status != 0:
pjsip_tx_data_dec_ref(tdata_auth)
_add_event("SIPRequestDidFail",
dict(obj=self, code=0,
reason="Could not create transaction for request with auth %s" %
_pj_status_to_str(status)))
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
return 0
self._tsx.mod_data[ua._module.id] = NULL
self._tsx = tsx_auth
self._tsx.mod_data[ua._module.id] = <void *> self
status = pjsip_tsx_send_msg(self._tsx, tdata_auth)
if status != 0:
pjsip_tx_data_dec_ref(tdata_auth)
_add_event("SIPRequestDidFail",
dict(obj=self, code=0,
reason="Could not send request with auth %s" % _pj_status_to_str(status)))
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
return 0
elif self._timeout is not None:
timeout_pj.sec = int(self._timeout)
timeout_pj.msec = (self._timeout * 1000) % 1000
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &timeout_pj)
if status == 0:
self._timer_active = 1
else:
event_dict = dict(obj=self)
if rdata != NULL:
# This shouldn't happen, but safety fist!
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
if self._tsx.status_code / 100 == 2:
if rdata != NULL:
if "Expires" in event_dict["headers"]:
expires = event_dict["headers"]["Expires"]
elif self.contact_header is not None:
for contact_header in event_dict["headers"].get("Contact", []):
if contact_header.uri == self.contact_header.uri and contact_header.expires is not None:
expires = contact_header.expires
if expires == -1:
expires = 0
for header in self.extra_headers:
if header.name == "Expires":
try:
expires = int(header.body)
except ValueError:
pass
break
event_dict["expires"] = expires
self._expire_time = datetime.now() + timedelta(seconds=expires)
_add_event("SIPRequestDidSucceed", event_dict)
else:
expires = 0
_add_event("SIPRequestDidFail", event_dict)
if expires == 0:
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
else:
timeout_pj.sec = max(1, expires - self.expire_warning_time, expires/2)
timeout_pj.msec = 0
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &timeout_pj)
if status == 0:
self._timer_active = 1
self.state = "EXPIRING"
self._expire_rest = max(1, expires - timeout_pj.sec)
else:
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
elif self._tsx.state == PJSIP_TSX_STATE_TERMINATED:
if self.state == "IN_PROGRESS":
if self._timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
_add_event("SIPRequestDidFail", dict(obj=self, code=self._tsx.status_code,
reason=_pj_str_to_bytes(self._tsx.status_text)))
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
self._tsx.mod_data[ua._module.id] = NULL
self._tsx = NULL
else:
pass
cdef int _cb_timer(self, PJSIPUA ua) except -1:
cdef pj_time_val expires
cdef int status
if self.state == "IN_PROGRESS":
pjsip_tsx_terminate(self._tsx, 408)
elif self.state == "EXPIRING":
if self._expire_rest > 0:
_add_event("SIPRequestWillExpire", dict(obj=self, expires=self._expire_rest))
expires.sec = self._expire_rest
expires.msec = 0
self._expire_rest = 0
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &expires)
if status == 0:
self._timer_active = 1
else:
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
else:
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
return 0
cdef class IncomingRequest:
def __cinit__(self, *args, **kwargs):
self.peer_address = None
def __dealloc__(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
return
if self._tsx != NULL:
pjsip_tsx_terminate(self._tsx, 500)
self._tsx = NULL
if self._tdata != NULL:
pjsip_tx_data_dec_ref(self._tdata)
self._tdata = NULL
def answer(self, int code, str reason=None, object extra_headers=None):
cdef bytes reason_bytes
cdef dict event_dict
cdef int status
cdef PJSIPUA ua = _get_ua()
if self.state != "incoming":
raise SIPCoreInvalidStateError('Can only answer an incoming request in the "incoming" state, '
'object is currently in the "%s" state' % self.state)
if code < 200 or code >= 700:
raise ValueError("Invalid SIP final response code: %d" % code)
self._tdata.msg.line.status.code = code
if reason is None:
self._tdata.msg.line.status.reason = pjsip_get_status_text(code)[0]
else:
- reason_bytes = reason.encode()
- pj_strdup2_with_null(self._tdata.pool, &self._tdata.msg.line.status.reason, reason_bytes)
+ pj_strdup2_with_null(self._tdata.pool, &self._tdata.msg.line.status.reason, reason.encode())
if extra_headers is not None:
_add_headers_to_tdata(self._tdata, extra_headers)
event_dict = dict(obj=self)
_pjsip_msg_to_dict(self._tdata.msg, event_dict)
status = pjsip_tsx_send_msg(self._tsx, self._tdata)
if status != 0:
raise PJSIPError("Could not send response", status)
self.state = "answered"
self._tdata = NULL
self._tsx = NULL
_add_event("SIPIncomingRequestSentResponse", event_dict)
cdef int init(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
cdef dict event_dict
cdef int status
status = pjsip_endpt_create_response(ua._pjsip_endpoint._obj, rdata, 500, NULL, &self._tdata)
if status != 0:
raise PJSIPError("Could not create response", status)
status = pjsip_tsx_create_uas(&ua._module, rdata, &self._tsx)
if status != 0:
pjsip_tx_data_dec_ref(self._tdata)
self._tdata = NULL
raise PJSIPError("Could not create transaction for incoming request", status)
pjsip_tsx_recv_msg(self._tsx, rdata)
self.state = "incoming"
self.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
event_dict = dict(obj=self)
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
_add_event("SIPIncomingRequestGotRequest", event_dict)
# callback functions
cdef void _Request_cb_tsx_state(pjsip_transaction *tsx, pjsip_event *event) with gil:
cdef PJSIPUA ua
cdef void *req_ptr
cdef Request req
cdef pjsip_rx_data *rdata = NULL
try:
ua = _get_ua()
except:
return
try:
req_ptr = tsx.mod_data[ua._module.id]
if req_ptr != NULL:
req = <object> req_ptr
if event.type == PJSIP_EVENT_RX_MSG:
rdata = event.body.rx_msg.rdata
elif event.type == PJSIP_EVENT_TSX_STATE and event.body.tsx_state.type == PJSIP_EVENT_RX_MSG:
rdata = event.body.tsx_state.src.rdata
req._cb_tsx_state(ua, rdata)
except:
ua._handle_exception(1)
cdef void _Request_cb_timer(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) with gil:
cdef PJSIPUA ua
cdef Request req
try:
ua = _get_ua()
except:
return
try:
if entry.user_data != NULL:
req = <object> entry.user_data
req._timer_active = 0
req._cb_timer(ua)
except:
ua._handle_exception(1)
diff --git a/sipsimple/core/_core.sdp.pxi b/sipsimple/core/_core.sdp.pxi
index f907348b..ec090e91 100644
--- a/sipsimple/core/_core.sdp.pxi
+++ b/sipsimple/core/_core.sdp.pxi
@@ -1,1227 +1,1233 @@
import re
from application.python.descriptor import WriteOnceAttribute
cdef object BaseSDPSession_richcmp(object self, object other, int op) with gil:
cdef int eq = 1
if op not in [2,3]:
return NotImplemented
if not isinstance(other, BaseSDPSession):
return NotImplemented
for attr in ("id", "version", "user", "net_type", "address_type", "address", "address",
"name", "connection", "start_time", "stop_time", "attributes", "bandwidth_info", "media"):
if getattr(self, attr) != getattr(other, attr):
eq = 0
break
if op == 2:
return bool(eq)
else:
return not eq
cdef pjmedia_sdp_session* _parse_sdp_session(str sdp):
cdef int status
cdef pjmedia_sdp_session *sdp_session
status = pjmedia_sdp_parse(_get_ua()._pjsip_endpoint._pool, _str_as_str(sdp), _str_as_size(sdp), &sdp_session)
if status != 0:
raise PJSIPError("failed to parse SDP", status)
return sdp_session
cdef class BaseSDPSession:
def __init__(self, *args, **kwargs):
raise TypeError("BaseSDPSession cannot be instantiated directly")
def __repr__(self):
return "%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)" % (self.__class__.__name__, self.address, self.id, self.version, self.user, self.net_type,
self.address_type, self.name, self.connection, self.start_time, self.stop_time, self.attributes, self.bandwidth_info, self.media)
def __str__(self):
cdef char cbuf[2048]
cdef int buf_len
buf_len = pjmedia_sdp_print(self.get_sdp_session(), cbuf, sizeof(cbuf))
if buf_len > -1:
return _pj_buf_len_to_str(cbuf, buf_len)
return ''
def __richcmp__(self, other, op):
return BaseSDPSession_richcmp(self, other, op)
cdef pjmedia_sdp_session* get_sdp_session(self):
self._sdp_session.media_count = len(self.media)
for index, m in enumerate(self.media):
if m is not None:
self._sdp_session.media[index] = (<BaseSDPMediaStream>m).get_sdp_media()
else:
self._sdp_session.media[index] = NULL
self._sdp_session.attr_count = len(self.attributes)
for index, attr in enumerate(self.attributes):
self._sdp_session.attr[index] = (<BaseSDPAttribute>attr).get_sdp_attribute()
self._sdp_session.bandw_count = len(self.bandwidth_info)
for index, info in enumerate(self.bandwidth_info):
self._sdp_session.bandw[index] = (<BaseSDPBandwidthInfo>info).get_sdp_bandwidth_info()
return &self._sdp_session
property has_ice_attributes:
def __get__(self):
return set([attr.name for attr in self.attributes]).issuperset(['ice-pwd', 'ice-ufrag'])
cdef class SDPSession(BaseSDPSession):
def __init__(self, str address not None, object id=None, object version=None, str user not None="-", str net_type not None="IN", str address_type not None="IP4",
str name not None=" ", SDPConnection connection=None, unsigned long start_time=0, unsigned long stop_time=0, list attributes=None, list bandwidth_info=None, list media=None):
cdef unsigned int version_id = 2208988800UL
cdef pj_time_val tv
pj_gettimeofday(&tv)
version_id += tv.sec
self.address = address
self.id = id if id is not None else version_id
self.version = version if version is not None else version_id
self.user = user
self.net_type = net_type
self.address_type = address_type
self.name = name
self.connection = connection
self.start_time = start_time
self.stop_time = stop_time
self.attributes = attributes if attributes is not None else []
self.bandwidth_info = bandwidth_info if bandwidth_info is not None else []
self.media = media if media is not None else []
@classmethod
def new(cls, BaseSDPSession sdp_session):
connection = SDPConnection.new(sdp_session.connection) if (sdp_session.connection is not None) else None
attributes = [SDPAttribute.new(attr) for attr in sdp_session.attributes]
bandwidth_info = [SDPBandwidthInfo.new(info) for info in sdp_session.bandwidth_info]
media = [SDPMediaStream.new(m) if m is not None else None for m in sdp_session.media]
return cls(sdp_session.address, sdp_session.id, sdp_session.version, sdp_session.user, sdp_session.net_type, sdp_session.address_type, sdp_session.name,
connection, sdp_session.start_time, sdp_session.stop_time, attributes, bandwidth_info, media)
@classmethod
def parse(cls, str sdp):
cdef pjmedia_sdp_session *sdp_session
sdp_session = _parse_sdp_session(sdp)
return SDPSession_create(sdp_session)
property address:
def __get__(self):
return self._address
def __set__(self, str address not None):
_str_to_pj_str(address.encode(), &self._sdp_session.origin.addr)
self._address = address
property id:
def __get__(self):
return self._sdp_session.origin.id
def __set__(self, unsigned int id):
self._sdp_session.origin.id = id
property version:
def __get__(self):
return self._sdp_session.origin.version
def __set__(self, unsigned int version):
self._sdp_session.origin.version = version
property user:
def __get__(self):
return self._user
def __set__(self, str user not None):
_str_to_pj_str(user.encode(), &self._sdp_session.origin.user)
self._user = user
property net_type:
def __get__(self):
return self._net_type
def __set__(self, str net_type not None):
_str_to_pj_str(net_type.encode(), &self._sdp_session.origin.net_type)
self._net_type = net_type
property address_type:
def __get__(self):
return self._address_type
def __set__(self, str address_type not None):
_str_to_pj_str(address_type.encode(), &self._sdp_session.origin.addr_type)
self._address_type = address_type
property name:
def __get__(self):
return self._name
def __set__(self, str name not None):
_str_to_pj_str(name.encode(), &self._sdp_session.name)
self._name = name
property connection:
def __get__(self):
return self._connection
def __set__(self, SDPConnection connection):
if connection is None:
self._sdp_session.conn = NULL
else:
self._sdp_session.conn = connection.get_sdp_connection()
self._connection = connection
property start_time:
def __get__(self):
return self._sdp_session.time.start
def __set__(self, unsigned long start_time):
self._sdp_session.time.start = start_time
property stop_time:
def __get__(self):
return self._sdp_session.time.stop
def __set__(self, unsigned long stop_time):
self._sdp_session.time.stop = stop_time
property attributes:
def __get__(self):
return self._attributes
def __set__(self, list attributes not None):
if len(attributes) > PJMEDIA_MAX_SDP_ATTR:
raise SIPCoreError("Too many attributes")
for attr in attributes:
if not isinstance(attr, SDPAttribute):
raise TypeError("Items in SDPSession attribute list must be SDPAttribute instancess")
if not isinstance(attributes, SDPAttributeList):
attributes = SDPAttributeList(attributes)
self._attributes = attributes
property bandwidth_info:
def __get__(self):
return self._bandwidth_info
def __set__(self, list infos not None):
if len(infos) > PJMEDIA_MAX_SDP_BANDW:
raise SIPCoreError("Too many bandwidth info attributes")
for info in infos:
if not isinstance(info, SDPBandwidthInfo):
raise TypeError("Items in SDPSession attribute list must be SDPBandwidthInfo instancess")
if not isinstance(infos, SDPBandwidthInfoList):
infos = SDPBandwidthInfoList(infos)
self._bandwidth_info = infos
property media:
def __get__(self):
return self._media
def __set__(self, list media not None):
if len(media) > PJMEDIA_MAX_SDP_MEDIA:
raise SIPCoreError("Too many media objects")
for m in media:
if m is not None and not isinstance(m, SDPMediaStream):
raise TypeError("Items in SDPSession media list must be SDPMediaStream instancess")
self._media = media
cdef int _update(self) except -1:
cdef SDPSession session
cdef SDPMediaStream media, old_media
session = SDPSession_create(&(<BaseSDPSession>self)._sdp_session)
if len(self._media) != len(session._media):
raise ValueError("Number of media streams in SDPSession got changed")
if len(self._attributes) > len(session._attributes):
raise ValueError("Number of attributes in SDPSession got reduced")
for attr in ("id", "version", "user", "net_type", "address_type",
"address", "name", "start_time", "stop_time"):
setattr(self, attr, getattr(session, attr))
if session._connection is None:
self.connection = None
elif self._connection is None or self._connection != session._connection:
self.connection = session._connection
for index, attribute in enumerate(session._attributes):
try:
old_attribute = self._attributes[index]
except IndexError:
self._attributes.append(attribute)
else:
if old_attribute != attribute:
self._attributes[index] = attribute
for index, info in enumerate(session._bandwidth_info):
try:
old_info = self._bandwidth_info[index]
except IndexError:
self._bandwidth_info.append(info)
else:
if old_info != info:
self._bandwidth_info[index] = info
for index, media in enumerate(session._media):
old_media = self._media[index]
if old_media is not None:
old_media._update(media)
cdef class FrozenSDPSession(BaseSDPSession):
def __init__(self, str address not None, object id=None, object version=None, str user not None="-", str net_type not None="IN", str address_type not None="IP4", str name not None=" ",
FrozenSDPConnection connection=None, unsigned long start_time=0, unsigned long stop_time=0, frozenlist attributes not None=frozenlist(), frozenlist bandwidth_info not None=frozenlist(),
frozenlist media not None=frozenlist()):
cdef unsigned int version_id = 2208988800UL
cdef pj_time_val tv
if not self.initialized:
if len(attributes) > PJMEDIA_MAX_SDP_ATTR:
raise SIPCoreError("Too many attributes")
for attr in attributes:
if not isinstance(attr, FrozenSDPAttribute):
raise TypeError("Items in FrozenSDPSession attribute list must be FrozenSDPAttribute instances")
if len(bandwidth_info) > PJMEDIA_MAX_SDP_BANDW:
raise SIPCoreError("Too many bandwidth info attributes")
for info in bandwidth_info:
if not isinstance(info, FrozenSDPBandwidthInfo):
raise TypeError("Items in FrozenSDPSession bandwidth info attribute list must be FrozenSDPBandwidthInfo instances")
if len(media) > PJMEDIA_MAX_SDP_MEDIA:
raise SIPCoreError("Too many media objects")
for m in media:
if not isinstance(m, FrozenSDPMediaStream):
raise TypeError("Items in FrozenSDPSession media list must be FrozenSDPMediaStream instancess")
pj_gettimeofday(&tv)
version_id += tv.sec
self.address = address
_str_to_pj_str(address.encode(), &self._sdp_session.origin.addr)
self.id = id if id is not None else version_id
self._sdp_session.origin.id = id if id is not None else version_id
self.version = version if version is not None else version_id
self._sdp_session.origin.version = version if version is not None else version_id
self.user = user
_str_to_pj_str(user.encode(), &self._sdp_session.origin.user)
self.net_type = net_type
_str_to_pj_str(net_type.encode(), &self._sdp_session.origin.net_type)
self.address_type = address_type
_str_to_pj_str(address_type.encode(), &self._sdp_session.origin.addr_type)
self.name = name
_str_to_pj_str(name.encode(), &self._sdp_session.name)
self.connection = connection
if connection is None:
self._sdp_session.conn = NULL
else:
self._sdp_session.conn = connection.get_sdp_connection()
self.start_time = start_time
self._sdp_session.time.start = start_time
self.stop_time = stop_time
self._sdp_session.time.stop = stop_time
self.attributes = FrozenSDPAttributeList(attributes) if not isinstance(attributes, FrozenSDPAttributeList) else attributes
self.bandwidth_info = FrozenSDPBandwidthInfoList(bandwidth_info) if not isinstance(bandwidth_info, FrozenSDPBandwidthInfo) else bandwidth_info
self.media = media
self.initialized = 1
@classmethod
def new(cls, BaseSDPSession sdp_session):
if isinstance(sdp_session, FrozenSDPSession):
return sdp_session
connection = FrozenSDPConnection.new(sdp_session.connection) if (sdp_session.connection is not None) else None
attributes = frozenlist([FrozenSDPAttribute.new(attr) for attr in sdp_session.attributes])
bandwidth_info = frozenlist([FrozenSDPBandwidthInfo.new(info) for info in sdp_session.bandwidth_info])
media = frozenlist([FrozenSDPMediaStream.new(m) for m in sdp_session.media])
return cls(sdp_session.address, sdp_session.id, sdp_session.version, sdp_session.user, sdp_session.net_type, sdp_session.address_type, sdp_session.name,
connection, sdp_session.start_time, sdp_session.stop_time, attributes, bandwidth_info, media)
@classmethod
def parse(cls, str sdp):
cdef pjmedia_sdp_session *sdp_session
sdp_session = _parse_sdp_session(sdp)
return FrozenSDPSession_create(sdp_session)
def __hash__(self):
return hash((self.address, self.id, self.version, self.user, self.net_type, self.address_type, self.name, self.connection, self.start_time, self.stop_time, self.attributes, self.bandwidth_info, self.media))
def __richcmp__(self, other, op):
return BaseSDPSession_richcmp(self, other, op)
class MediaCodec(object):
name = WriteOnceAttribute()
rate = WriteOnceAttribute()
def __init__(self, name, rate):
self.name = name
self.rate = int(rate)
def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, self.name, self.rate)
def __str__(self):
return "%s/%s" % (self.name, self.rate)
def __hash__(self):
return hash(self.name)
def __eq__(self, other):
if isinstance(other, MediaCodec):
return self.name.lower() == other.name.lower() and self.rate == other.rate
elif isinstance(other, basestring):
if '/' in other:
return self.__str__().lower() == other.lower()
else:
return self.name.lower() == other.lower()
return False
def __ne__(self, other):
return not self.__eq__(other)
cdef object BaseSDPMediaStream_richcmp(object self, object other, int op) with gil:
cdef int eq = 1
if op not in [2,3]:
return NotImplemented
if not isinstance(other, BaseSDPMediaStream):
return NotImplemented
for attr in ("media", "port", "port_count", "transport", "formats", "connection", "attributes", "bandwidth_info"):
if getattr(self, attr) != getattr(other, attr):
eq = 0
break
if op == 2:
return bool(eq)
else:
return not eq
cdef class BaseSDPMediaStream:
rtpmap_re = re.compile(r"""^(?P<type>\d+)\s+(?P<name>[-\w]+)/(?P<rate>\d+)(?:/\w+)?$""", re.IGNORECASE | re.MULTILINE)
rtp_mappings = { 0: MediaCodec('PCMU', 8000),
3: MediaCodec('GSM', 8000),
4: MediaCodec('G723', 8000),
5: MediaCodec('DVI4', 8000),
6: MediaCodec('DVI4', 16000),
7: MediaCodec('LPC', 8000),
8: MediaCodec('PCMA', 8000),
9: MediaCodec('G722', 8000),
10: MediaCodec('L16', 44100), # 2 channels
11: MediaCodec('L16', 44100), # 1 channel
12: MediaCodec('QCELP', 8000),
13: MediaCodec('CN', 8000),
14: MediaCodec('MPA', 90000),
15: MediaCodec('G728', 8000),
16: MediaCodec('DVI4', 11025),
17: MediaCodec('DVI4', 22050),
18: MediaCodec('G729', 8000)}
def __init__(self, *args, **kwargs):
raise TypeError("BaseSDPMediaStream cannot be instantiated directly")
def __repr__(self):
return "%s(%r, %r, %r, %r, %r, %r, %r, %r)" % (self.__class__.__name__, self.media, self.port, self.transport,
self.port_count, self.formats, self.connection, self.attributes, self.bandwidth_info)
def __richcmp__(self, other, op):
return BaseSDPMediaStream_richcmp(self, other, op)
property direction:
def __get__(self):
for attribute in self.attributes:
if attribute.name in ("sendrecv", "sendonly", "recvonly", "inactive"):
return attribute.name
return "sendrecv"
property has_ice_attributes:
def __get__(self):
return set([attr.name for attr in self.attributes]).issuperset(['ice-pwd', 'ice-ufrag'])
property has_ice_candidates:
def __get__(self):
return 'candidate' in self.attributes
cdef pjmedia_sdp_media* get_sdp_media(self):
self._sdp_media.attr_count = len(self.attributes)
for index, attr in enumerate(self.attributes):
self._sdp_media.attr[index] = (<BaseSDPAttribute>attr).get_sdp_attribute()
self._sdp_media.bandw_count = len(self.bandwidth_info)
for index, info in enumerate(self.bandwidth_info):
self._sdp_media.bandw[index] = (<BaseSDPBandwidthInfo>info).get_sdp_bandwidth_info()
return &self._sdp_media
cdef class SDPMediaStream(BaseSDPMediaStream):
def __init__(self, str media not None, int port, str transport not None, int port_count=1, list formats=None,
SDPConnection connection=None, list attributes=None, list bandwidth_info=None):
self.media = media
self.port = port
self.transport = transport
self.port_count = port_count
self.formats = formats if formats is not None else []
self.connection = connection
self.attributes = attributes if attributes is not None else []
self.bandwidth_info = bandwidth_info if bandwidth_info is not None else []
@classmethod
def new(cls, BaseSDPMediaStream sdp_media):
connection = SDPConnection.new(sdp_media.connection) if (sdp_media.connection is not None) else None
attributes = [SDPAttribute.new(attr) for attr in sdp_media.attributes]
bandwidth_info = [SDPBandwidthInfo.new(bi) for bi in sdp_media.bandwidth_info]
return cls(sdp_media.media, sdp_media.port, sdp_media.transport, sdp_media.port_count, list(sdp_media.formats),
connection, attributes, bandwidth_info)
property media:
def __get__(self):
return self._media
def __set__(self, str media not None):
_str_to_pj_str(media.encode(), &self._sdp_media.desc.media)
self._media = media
property port:
def __get__(self):
return self._sdp_media.desc.port
def __set__(self, int port):
self._sdp_media.desc.port = port
property transport:
def __get__(self):
return self._transport
def __set__(self, str transport not None):
_str_to_pj_str(transport.encode(), &self._sdp_media.desc.transport)
self._transport = transport
property port_count:
def __get__(self):
return self._sdp_media.desc.port_count
def __set__(self, int port_count):
self._sdp_media.desc.port_count = port_count
property formats:
def __get__(self):
return self._formats
def __set__(self, list formats not None):
if len(formats) > PJMEDIA_MAX_SDP_FMT:
raise SIPCoreError("Too many formats")
self._sdp_media.desc.fmt_count = len(formats)
for index, format in enumerate(formats):
_str_to_pj_str(format.encode(), &self._sdp_media.desc.fmt[index])
self._formats = formats
property codec_list:
def __get__(self):
return self._codec_list
property connection:
def __get__(self):
return self._connection
def __set__(self, SDPConnection connection):
if connection is None:
self._sdp_media.conn = NULL
else:
self._sdp_media.conn = connection.get_sdp_connection()
self._connection = connection
property attributes:
def __get__(self):
return self._attributes
def __set__(self, list attributes not None):
if len(attributes) > PJMEDIA_MAX_SDP_ATTR:
raise SIPCoreError("Too many attributes")
for attr in attributes:
if not isinstance(attr, SDPAttribute):
raise TypeError("Items in SDPMediaStream attribute list must be SDPAttribute instances")
if not isinstance(attributes, SDPAttributeList):
attributes = SDPAttributeList(attributes)
self._attributes = attributes
if self._media in ("audio", "video"):
rtp_mappings = self.rtp_mappings.copy()
rtpmap_lines = '\n'.join([attr.value for attr in attributes if attr.name=='rtpmap']) # iterators are not supported -Dan
rtpmap_codecs = dict([(int(type), MediaCodec(name, rate)) for type, name, rate in self.rtpmap_re.findall(rtpmap_lines)])
rtp_mappings.update(rtpmap_codecs)
self._codec_list = [rtp_mappings.get(int(format), MediaCodec('Unknown', 0)) for format in self.formats]
else:
self._codec_list = list()
property bandwidth_info:
def __get__(self):
return self._bandwidth_info
def __set__(self, list infos not None):
if len(infos) > PJMEDIA_MAX_SDP_BANDW:
raise SIPCoreError("Too many bandwidth information attributes")
for info in infos:
if not isinstance(info, SDPBandwidthInfo):
raise TypeError("Items in SDPMediaStream bandwidth_info list must be SDPBandwidthInfo instances")
if not isinstance(infos, SDPBandwidthInfoList):
infos = SDPBandwidthInfoList(infos)
self._bandwidth_info = infos
cdef int _update(self, SDPMediaStream media) except -1:
if len(self._attributes) > len(media._attributes):
raise ValueError("Number of attributes in SDPMediaStream got reduced")
if len(self._bandwidth_info) > len(media._bandwidth_info):
raise ValueError("Number of bandwidth info attributes in SDPMediaStream got reduced")
for attr in ("media", "port", "transport", "port_count", "formats"):
setattr(self, attr, getattr(media, attr))
if media._connection is None:
self.connection = None
elif self._connection is None or self._connection != media.connection:
self.connection = media._connection
for index, attribute in enumerate(media._attributes):
try:
old_attribute = self._attributes[index]
except IndexError:
self._attributes.append(attribute)
else:
if old_attribute != attribute:
self._attributes[index] = attribute
for index, info in enumerate(media._bandwidth_info):
try:
old_info = self._bandwidth_info[index]
except IndexError:
self._bandwidth_info.append(info)
else:
if old_info != info:
self._bandwidth_info[index] = info
cdef class FrozenSDPMediaStream(BaseSDPMediaStream):
def __init__(self, str media not None, int port, str transport not None, int port_count=1, frozenlist formats not None=frozenlist(),
FrozenSDPConnection connection=None, frozenlist attributes not None=frozenlist(), frozenlist bandwidth_info not None=frozenlist()):
if not self.initialized:
if len(formats) > PJMEDIA_MAX_SDP_FMT:
raise SIPCoreError("Too many formats")
if len(attributes) > PJMEDIA_MAX_SDP_ATTR:
raise SIPCoreError("Too many attributes")
for attr in attributes:
if not isinstance(attr, FrozenSDPAttribute):
raise TypeError("Items in FrozenSDPMediaStream attribute list must be FrozenSDPAttribute instances")
if len(bandwidth_info) > PJMEDIA_MAX_SDP_BANDW:
raise SIPCoreError("Too many bandwidth info attributes")
for info in bandwidth_info:
if not isinstance(info, FrozenSDPBandwidthInfo):
raise TypeError("Items in FrozenSDPMediaStream bandwidth info list must be FrozenSDPBandwidthInfo instances")
self.media = media
_str_to_pj_str(media.encode(), &self._sdp_media.desc.media)
self.port = port
self._sdp_media.desc.port = port
self.transport = transport
_str_to_pj_str(transport.encode(), &self._sdp_media.desc.transport)
self.port_count = port_count
self._sdp_media.desc.port_count = port_count
self.formats = formats
self._sdp_media.desc.fmt_count = len(self.formats)
for index, format in enumerate(self.formats):
_str_to_pj_str(format.encode(), &self._sdp_media.desc.fmt[index])
self.connection = connection
if connection is None:
self._sdp_media.conn = NULL
else:
self._sdp_media.conn = connection.get_sdp_connection()
self.attributes = FrozenSDPAttributeList(attributes) if not isinstance(attributes, FrozenSDPAttributeList) else attributes
if self.media in ("audio", "video"):
rtp_mappings = self.rtp_mappings.copy()
rtpmap_lines = '\n'.join([attr.value for attr in attributes if attr.name=='rtpmap']) # iterators are not supported -Dan
rtpmap_codecs = dict([(int(type), MediaCodec(name, rate)) for type, name, rate in self.rtpmap_re.findall(rtpmap_lines)])
rtp_mappings.update(rtpmap_codecs)
self.codec_list = frozenlist([rtp_mappings.get(int(format) if format.isdigit() else None, MediaCodec('Unknown', 0)) for format in self.formats])
else:
self.codec_list = frozenlist()
self.bandwidth_info = FrozenSDPBandwidthInfoList(bandwidth_info) if not isinstance(bandwidth_info, FrozenSDPBandwidthInfoList) else bandwidth_info
self.initialized = 1
@classmethod
def new(cls, BaseSDPMediaStream sdp_media):
if isinstance(sdp_media, FrozenSDPMediaStream):
return sdp_media
connection = FrozenSDPConnection.new(sdp_media.connection) if (sdp_media.connection is not None) else None
attributes = frozenlist([FrozenSDPAttribute.new(attr) for attr in sdp_media.attributes])
bandwidth_info = frozenlist([FrozenSDPBandwidthInfo.new(info) for info in sdp_media.bandwidth_info])
return cls(sdp_media.media, sdp_media.port, sdp_media.transport, sdp_media.port_count,
frozenlist(sdp_media.formats), connection, attributes, bandwidth_info)
def __hash__(self):
return hash((self.media, self.port, self.transport, self.port_count, self.formats, self.connection, self.attributes, self.bandwidth_info))
def __richcmp__(self, other, op):
return BaseSDPMediaStream_richcmp(self, other, op)
cdef object BaseSDPConnection_richcmp(object self, object other, int op) with gil:
cdef int eq = 1
if op not in [2,3]:
return NotImplemented
if not isinstance(other, BaseSDPConnection):
return NotImplemented
for attr in ("net_type", "address_type", "address"):
if getattr(self, attr) != getattr(other, attr):
eq = 0
break
if op == 2:
return bool(eq)
else:
return not eq
cdef class BaseSDPConnection:
def __init__(self, *args, **kwargs):
raise TypeError("BaseSDPConnection cannot be instantiated directly")
def __repr__(self):
return "%s(%r, %r, %r)" % (self.__class__.__name__, self.address, self.net_type, self.address_type)
def __richcmp__(self, other, op):
return BaseSDPConnection_richcmp(self, other, op)
cdef pjmedia_sdp_conn* get_sdp_connection(self):
return &self._sdp_connection
cdef class SDPConnection(BaseSDPConnection):
def __init__(self, str address not None, str net_type not None="IN", str address_type not None="IP4"):
self.address = address
self.net_type = net_type
self.address_type = address_type
@classmethod
def new(cls, BaseSDPConnection sdp_connection):
return cls(sdp_connection.address, sdp_connection.net_type, sdp_connection.address_type)
property address:
def __get__(self):
return self._address
def __set__(self, str address not None):
_str_to_pj_str(address.encode(), &self._sdp_connection.addr)
self._address = address
property net_type:
def __get__(self):
return self._net_type
def __set__(self, str net_type not None):
_str_to_pj_str(net_type.encode(), &self._sdp_connection.net_type)
self._net_type = net_type
property address_type:
def __get__(self):
return self._address_type
def __set__(self, str address_type not None):
_str_to_pj_str(address_type.encode(), &self._sdp_connection.addr_type)
self._address_type = address_type
cdef class FrozenSDPConnection(BaseSDPConnection):
def __init__(self, str address not None, str net_type not None="IN", str address_type not None="IP4"):
if not self.initialized:
_str_to_pj_str(address.encode(), &self._sdp_connection.addr)
_str_to_pj_str(net_type.encode(), &self._sdp_connection.net_type)
_str_to_pj_str(address_type.encode(), &self._sdp_connection.addr_type)
self.address = address
self.net_type = net_type
self.address_type = address_type
self.initialized = 1
@classmethod
def new(cls, BaseSDPConnection sdp_connection):
if isinstance(sdp_connection, FrozenSDPConnection):
return sdp_connection
return cls(sdp_connection.address, sdp_connection.net_type, sdp_connection.address_type)
def __hash__(self):
return hash((self.address, self.net_type, self.address_type))
def __richcmp__(self, other, op):
return BaseSDPConnection_richcmp(self, other, op)
cdef class SDPAttributeList(list):
def __contains__(self, item):
if isinstance(item, BaseSDPAttribute):
return list.__contains__(self, item)
else:
return item in [attr.name for attr in self]
def getall(self, name):
return [attr.value for attr in self if attr.name == name]
def getfirst(self, name, default=None):
for attr in self:
if attr.name == name:
return attr.value
return default
cdef class FrozenSDPAttributeList(frozenlist):
def __contains__(self, item):
if isinstance(item, BaseSDPAttribute):
return list.__contains__(self, item)
else:
return item in [attr.name for attr in self]
def getall(self, name):
return [attr.value for attr in self if attr.name == name]
def getfirst(self, name, default=None):
for attr in self:
if attr.name == name:
return attr.value
return default
cdef object BaseSDPAttribute_richcmp(object self, object other, int op) with gil:
cdef int eq = 1
if op not in [2,3]:
return NotImplemented
if not isinstance(other, BaseSDPAttribute):
return NotImplemented
for attr in ("name", "value"):
if getattr(self, attr) != getattr(other, attr):
eq = 0
break
if op == 2:
return bool(eq)
else:
return not eq
cdef class BaseSDPAttribute:
def __init__(self, *args, **kwargs):
raise TypeError("BaseSDPAttribute cannot be instantiated directly")
def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, self.name, self.value)
def __richcmp__(self, other, op):
return BaseSDPAttribute_richcmp(self, other, op)
cdef pjmedia_sdp_attr* get_sdp_attribute(self):
return &self._sdp_attribute
cdef class SDPAttribute(BaseSDPAttribute):
def __init__(self, str name not None, str value not None):
self.name = name
self.value = value
@classmethod
def new(cls, BaseSDPAttribute sdp_attribute):
return cls(sdp_attribute.name, sdp_attribute.value)
property name:
def __get__(self):
return self._name
def __set__(self, str name not None):
_str_to_pj_str(name.encode(), &self._sdp_attribute.name)
self._name = name
property value:
def __get__(self):
return self._value
def __set__(self, str value not None):
_str_to_pj_str(value.encode(), &self._sdp_attribute.value)
self._value = value
cdef class FrozenSDPAttribute(BaseSDPAttribute):
def __init__(self, str name not None, str value not None):
if not self.initialized:
_str_to_pj_str(name.encode(), &self._sdp_attribute.name)
_str_to_pj_str(value.encode(), &self._sdp_attribute.value)
self.name = name
self.value = value
self.initialized = 1
@classmethod
def new(cls, BaseSDPAttribute sdp_attribute):
if isinstance(sdp_attribute, FrozenSDPAttribute):
return sdp_attribute
return cls(sdp_attribute.name, sdp_attribute.value)
def __hash__(self):
return hash((self.name, self.value))
def __richcmp__(self, other, op):
return BaseSDPAttribute_richcmp(self, other, op)
cdef class SDPBandwidthInfoList(list):
def __contains__(self, item):
if isinstance(item, BaseSDPBandwidthInfo):
return list.__contains__(self, item)
else:
return item in [attr.name.decode() for attr in self]
cdef class FrozenSDPBandwidthInfoList(frozenlist):
def __contains__(self, item):
if isinstance(item, BaseSDPBandwidthInfo):
return list.__contains__(self, item)
else:
return item in [info.modifier.decode() for info in self]
cdef object BaseSDPBandwidthInfo_richcmp(object self, object other, int op) with gil:
cdef int eq = 1
if op not in [2,3]:
return NotImplemented
if not isinstance(other, BaseSDPBandwidthInfo):
return NotImplemented
for attr in ("modifier", "value"):
if getattr(self, attr) != getattr(other, attr):
eq = 0
break
if op == 2:
return bool(eq)
else:
return not eq
cdef class BaseSDPBandwidthInfo:
def __init__(self, *args, **kwargs):
raise TypeError("BaseSDPBandwidthInfo cannot be instantiated directly")
def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, self.modifier, self.value)
def __richcmp__(self, other, op):
return BaseSDPBandwidthInfo_richcmp(self, other, op)
cdef pjmedia_sdp_bandw* get_sdp_bandwidth_info(self):
return &self._sdp_bandwidth_info
cdef class SDPBandwidthInfo(BaseSDPBandwidthInfo):
def __init__(self, str modifier not None, object value not None):
self.modifier = modifier
self.value = value
@classmethod
def new(cls, BaseSDPBandwidthInfo sdp_bandwidth_info):
return cls(sdp_bandwidth_info.modifier, sdp_bandwidth_info.value)
property modifier:
def __get__(self):
return self._modifier
def __set__(self, str modifier not None):
_str_to_pj_str(modifier.encode(), &self._sdp_bandwidth_info.modifier)
self._modifier = modifier
property value:
def __get__(self):
return self._value
def __set__(self, object value not None):
self._value = value
self._sdp_bandwidth_info.value = self._value
cdef class FrozenSDPBandwidthInfo(BaseSDPBandwidthInfo):
def __init__(self, str modifier not None, object value not None):
if not self.initialized:
_str_to_pj_str(modifier.encode(), &self._sdp_bandwidth_info.modifier)
self.modifier = modifier
self._sdp_bandwidth_info.value = value
self.value = value
self.initialized = 1
@classmethod
def new(cls, BaseSDPBandwidthInfo sdp_bandwidth_info):
if isinstance(sdp_bandwidth_info, FrozenSDPBandwidthInfo):
return sdp_bandwidth_info
return cls(sdp_bandwidth_info.modifier, sdp_bandwidth_info.value)
def __hash__(self):
return hash((self.modifier, self.value))
def __richcmp__(self, other, op):
return BaseSDPBandwidthInfo_richcmp(self, other, op)
# Factory functions
#
cdef SDPSession SDPSession_create(pjmedia_sdp_session_ptr_const pj_session):
cdef SDPConnection connection = None
cdef int i
if pj_session.conn != NULL:
connection = SDPConnection_create(pj_session.conn)
+ print('pj_session.origin.user %s' % pj_session.origin.user )
+ print('pj_session.origin.user %s' % _pj_str_to_str(pj_session.origin.user))
+ print('pj_session.origin.addr_type %s' % pj_session.origin.addr_type)
+ print('pj_session.origin.addr_type %s' % _pj_str_to_bytes(pj_session.origin.addr_type))
+ print('pj_session.origin.net_type %s' % pj_session.origin.net_type )
+ print('pj_session.origin.name %s' % pj_session.name )
return SDPSession(_pj_str_to_str(pj_session.origin.addr),
pj_session.origin.id,
pj_session.origin.version,
_pj_str_to_str(pj_session.origin.user),
_pj_str_to_str(pj_session.origin.net_type),
_pj_str_to_str(pj_session.origin.addr_type),
_pj_str_to_str(pj_session.name),
connection,
pj_session.time.start,
pj_session.time.stop,
[SDPAttribute_create(pj_session.attr[i]) for i in range(pj_session.attr_count)],
[SDPBandwidthInfo_create(pj_session.bandw[i]) for i in range(pj_session.bandw_count)],
[SDPMediaStream_create(pj_session.media[i]) if pj_session.media[i] != NULL else None for i in range(pj_session.media_count)])
cdef FrozenSDPSession FrozenSDPSession_create(pjmedia_sdp_session_ptr_const pj_session):
cdef FrozenSDPConnection connection = None
cdef int i
if pj_session.conn != NULL:
connection = FrozenSDPConnection_create(pj_session.conn)
return FrozenSDPSession(_pj_str_to_str(pj_session.origin.addr),
pj_session.origin.id,
pj_session.origin.version,
_pj_str_to_str(pj_session.origin.user),
_pj_str_to_str(pj_session.origin.net_type),
_pj_str_to_str(pj_session.origin.addr_type),
_pj_str_to_str(pj_session.name),
connection,
pj_session.time.start,
pj_session.time.stop,
frozenlist([FrozenSDPAttribute_create(pj_session.attr[i]) for i in range(pj_session.attr_count)]),
frozenlist([FrozenSDPBandwidthInfo_create(pj_session.bandw[i]) for i in range(pj_session.bandw_count)]),
frozenlist([FrozenSDPMediaStream_create(pj_session.media[i]) if pj_session.media[i] != NULL else None for i in range(pj_session.media_count)]))
cdef SDPMediaStream SDPMediaStream_create(pjmedia_sdp_media *pj_media):
cdef SDPConnection connection = None
cdef int i
if pj_media.conn != NULL:
connection = SDPConnection_create(pj_media.conn)
return SDPMediaStream(_pj_str_to_str(pj_media.desc.media),
pj_media.desc.port,
_pj_str_to_str(pj_media.desc.transport),
pj_media.desc.port_count,
[_pj_str_to_str(pj_media.desc.fmt[i]) for i in range(pj_media.desc.fmt_count)],
connection,
[SDPAttribute_create(pj_media.attr[i]) for i in range(pj_media.attr_count)],
[SDPBandwidthInfo_create(pj_media.bandw[i]) for i in range(pj_media.bandw_count)])
cdef FrozenSDPMediaStream FrozenSDPMediaStream_create(pjmedia_sdp_media *pj_media):
cdef FrozenSDPConnection connection = None
cdef int i
if pj_media.conn != NULL:
connection = FrozenSDPConnection_create(pj_media.conn)
return FrozenSDPMediaStream(_pj_str_to_str(pj_media.desc.media),
pj_media.desc.port,
_pj_str_to_str(pj_media.desc.transport),
pj_media.desc.port_count,
frozenlist([_pj_str_to_str(pj_media.desc.fmt[i]) for i in range(pj_media.desc.fmt_count)]),
connection,
frozenlist([FrozenSDPAttribute_create(pj_media.attr[i]) for i in range(pj_media.attr_count)]),
frozenlist([FrozenSDPBandwidthInfo_create(pj_media.bandw[i]) for i in range(pj_media.bandw_count)]))
cdef SDPConnection SDPConnection_create(pjmedia_sdp_conn *pj_conn):
return SDPConnection(_pj_str_to_str(pj_conn.addr), _pj_str_to_str(pj_conn.net_type),
_pj_str_to_str(pj_conn.addr_type))
cdef FrozenSDPConnection FrozenSDPConnection_create(pjmedia_sdp_conn *pj_conn):
return FrozenSDPConnection(_pj_str_to_str(pj_conn.addr), _pj_str_to_str(pj_conn.net_type),
_pj_str_to_str(pj_conn.addr_type))
cdef SDPAttribute SDPAttribute_create(pjmedia_sdp_attr *pj_attr):
return SDPAttribute(_pj_str_to_str(pj_attr.name), _pj_str_to_str(pj_attr.value))
cdef FrozenSDPAttribute FrozenSDPAttribute_create(pjmedia_sdp_attr *pj_attr):
return FrozenSDPAttribute(_pj_str_to_str(pj_attr.name), _pj_str_to_str(pj_attr.value))
cdef SDPBandwidthInfo SDPBandwidthInfo_create(pjmedia_sdp_bandw *pj_bandw):
return SDPBandwidthInfo(_pj_str_to_str(pj_bandw.modifier), int(pj_bandw.value))
cdef FrozenSDPBandwidthInfo FrozenSDPBandwidthInfo_create(pjmedia_sdp_bandw *pj_bandw):
return FrozenSDPBandwidthInfo(_pj_str_to_str(pj_bandw.modifier), int(pj_bandw.value))
# SDP negotiator
#
cdef class SDPNegotiator:
def __cinit__(self, *args, **kwargs):
cdef pj_pool_t *pool
cdef bytes pool_name
cdef PJSIPUA ua
ua = _get_ua()
pool_name = b"SDPNegotiator_%d" % id(self)
pool = ua.create_memory_pool(pool_name, 4096, 4096)
self._pool = pool
self._neg = NULL
def __dealloc__(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
ua.release_memory_pool(self._pool)
self._pool = NULL
@classmethod
def create_with_local_offer(cls, BaseSDPSession sdp_session):
cdef int status
cdef pjmedia_sdp_neg *neg
cdef pj_pool_t *pool
cdef SDPNegotiator obj
obj = cls()
pool = obj._pool
status = pjmedia_sdp_neg_create_w_local_offer(pool, sdp_session.get_sdp_session(), &neg)
if status != 0:
raise PJSIPError("failed to create SDPNegotiator with local offer", status)
obj._neg = neg
return obj
@classmethod
def create_with_remote_offer(cls, BaseSDPSession sdp_session):
cdef int status
cdef pjmedia_sdp_neg *neg
cdef pj_pool_t *pool
cdef SDPNegotiator obj
obj = cls()
pool = obj._pool
status = pjmedia_sdp_neg_create_w_remote_offer(pool, NULL, sdp_session.get_sdp_session(), &neg)
if status != 0:
raise PJSIPError("failed to create SDPNegotiator with remote offer", status)
obj._neg = neg
return obj
def __repr__(self):
return "%s, state=%s" % (self.__class__.__name__, self.state)
property state:
def __get__(self):
if self._neg == NULL:
return None
return _buf_to_str(pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(self._neg)))
property active_local:
def __get__(self):
cdef int status
cdef pjmedia_sdp_session_ptr_const sdp
if self._neg == NULL:
return None
status = pjmedia_sdp_neg_get_active_local(self._neg, &sdp)
if status != 0:
return None
return FrozenSDPSession_create(sdp)
property active_remote:
def __get__(self):
cdef int status
cdef pjmedia_sdp_session_ptr_const sdp
if self._neg == NULL:
return None
status = pjmedia_sdp_neg_get_active_remote(self._neg, &sdp)
if status != 0:
return None
return FrozenSDPSession_create(sdp)
property current_local:
def __get__(self):
cdef int status
cdef pjmedia_sdp_session_ptr_const sdp
if self._neg == NULL:
return None
status = pjmedia_sdp_neg_get_neg_local(self._neg, &sdp)
if status != 0:
return None
return FrozenSDPSession_create(sdp)
property current_remote:
def __get__(self):
cdef int status
cdef pjmedia_sdp_session_ptr_const sdp
if self._neg == NULL:
return None
status = pjmedia_sdp_neg_get_neg_remote(self._neg, &sdp)
if status != 0:
return None
return FrozenSDPSession_create(sdp)
def _check_self(self):
if self._neg == NULL:
raise RuntimeError('SDPNegotiator was not properly initialized')
def set_local_answer(self, BaseSDPSession sdp_session):
self._check_self()
cdef int status
cdef pj_pool_t *pool = self._pool
status = pjmedia_sdp_neg_set_local_answer(pool, self._neg, sdp_session.get_sdp_session())
if status != 0:
raise PJSIPError("failed to set local answer", status)
def set_local_offer(self, BaseSDPSession sdp_session):
# PJSIP has an asymmetric API here. This function will modify the local session with the new SDP and treat it as a local offer.
self._check_self()
cdef int status
cdef pj_pool_t *pool = self._pool
status = pjmedia_sdp_neg_modify_local_offer(pool, self._neg, sdp_session.get_sdp_session())
if status != 0:
raise PJSIPError("failed to set local offer", status)
def set_remote_answer(self, BaseSDPSession sdp_session):
self._check_self()
cdef int status
cdef pj_pool_t *pool = self._pool
status = pjmedia_sdp_neg_set_remote_answer(pool, self._neg, sdp_session.get_sdp_session())
if status != 0:
raise PJSIPError("failed to set remote answer", status)
def set_remote_offer(self, BaseSDPSession sdp_session):
self._check_self()
cdef int status
cdef pj_pool_t *pool = self._pool
status = pjmedia_sdp_neg_set_remote_offer(pool, self._neg, sdp_session.get_sdp_session())
if status != 0:
raise PJSIPError("failed to set remote offer", status)
def cancel_offer(self):
self._check_self()
cdef int status
status = pjmedia_sdp_neg_cancel_offer(self._neg)
if status != 0:
raise PJSIPError("failed to cancel offer", status)
def negotiate(self):
self._check_self()
cdef int status
cdef pj_pool_t *pool = self._pool
status = pjmedia_sdp_neg_negotiate(pool, self._neg, 0)
if status != 0:
raise PJSIPError("SDP negotiation failed", status)
diff --git a/sipsimple/core/_core.util.pxi b/sipsimple/core/_core.util.pxi
index 53d9f9ae..e62513bf 100644
--- a/sipsimple/core/_core.util.pxi
+++ b/sipsimple/core/_core.util.pxi
@@ -1,433 +1,433 @@
import platform
import re
import sys
from application.version import Version
cdef class PJSTR:
def __cinit__(self, str):
self.str = str
_str_to_pj_str(str, &self.pj_str)
def __str__(self):
return self.str
cdef class SIPStatusMessages:
cdef object _default_status
def __cinit__(self, *args, **kwargs):
self._default_status = _pj_str_to_str(pjsip_get_status_text(0)[0])
def __getitem__(self, int val):
cdef object _status
_status = _pj_str_to_str(pjsip_get_status_text(val)[0])
if _status == self._default_status:
raise IndexError("Unknown SIP response code: %d" % val)
return _status
cdef class frozenlist:
def __cinit__(self, *args, **kw):
self.list = list()
self.initialized = 0
self.hash = 0
def __init__(self, *args, **kw):
if not self.initialized:
self.list = list(*args, **kw)
self.initialized = 1
self.hash = hash(tuple(self.list))
def __reduce__(self):
return (self.__class__, (self.list,), None)
def __repr__(self):
return "frozenlist(%r)" % self.list
def __len__(self):
return self.list.__len__()
def __hash__(self):
return self.hash
def __iter__(self):
return self.list.__iter__()
def __cmp__(self, frozenlist other):
return self.list.__cmp__(other.list)
def __richcmp__(frozenlist self, other, op):
if isinstance(other, frozenlist):
other = (<frozenlist>other).list
if op == 0:
return self.list.__cmp__(other) < 0
elif op == 1:
return self.list.__cmp__(other) <= 0
elif op == 2:
return self.list.__eq__(other)
elif op == 3:
return self.list.__ne__(other)
elif op == 4:
return self.list.__cmp__(other) > 0
elif op == 5:
return self.list.__cmp__(other) >= 0
else:
return NotImplemented
def __contains__(self, item):
return self.list.__contains__(item)
def __getitem__(self, key):
return self.list.__getitem__(key)
def __add__(first, second):
if isinstance(first, frozenlist):
first = (<frozenlist>first).list
if isinstance(second, frozenlist):
second = (<frozenlist>second).list
return frozenlist(first+second)
def __mul__(first, second):
if isinstance(first, frozenlist):
first = (<frozenlist>first).list
if isinstance(second, frozenlist):
second = (<frozenlist>second).list
return frozenlist(first*second)
def __reversed__(self):
return self.list.__reversed__()
def count(self, elem):
return self.list.count(elem)
def index(self, elem):
return self.list.index(elem)
cdef class frozendict:
def __cinit__(self, *args, **kw):
self.dict = dict()
self.initialized = 0
def __init__(self, *args, **kw):
if not self.initialized:
self.dict = dict(*args, **kw)
self.initialized = 1
self.hash = hash(tuple(self.dict.iteritems()))
def __reduce__(self):
return (self.__class__, (self.dict,), None)
def __repr__(self):
return "frozendict(%r)" % self.dict
def __len__(self):
return self.dict.__len__()
def __hash__(self):
return self.hash
def __iter__(self):
return self.dict.__iter__()
def __cmp__(self, frozendict other):
return self.dict.__cmp__(other.dict)
def __richcmp__(frozendict self, other, op):
if isinstance(other, frozendict):
other = (<frozendict>other).dict
if op == 0:
return self.dict.__cmp__(other) < 0
elif op == 1:
return self.dict.__cmp__(other) <= 0
elif op == 2:
return self.dict.__eq__(other)
elif op == 3:
return self.dict.__ne__(other)
elif op == 4:
return self.dict.__cmp__(other) > 0
elif op == 5:
return self.dict.__cmp__(other) >= 0
else:
return NotImplemented
def __contains__(self, item):
return self.dict.__contains__(item)
def __getitem__(self, key):
return self.dict.__getitem__(key)
def copy(self):
return self
def get(self, *args):
return self.dict.get(*args)
def has_key(self, key):
return self.dict.has_key(key)
def items(self):
return list(self.dict.items())
def iteritems(self):
return list(self.dict.items())
def iterkeys(self):
return list(self.dict.keys())
def itervalues(self):
return list(self.dict.values())
def keys(self):
return list(self.dict.keys())
def values(self):
return list(self.dict.values())
# functions
cdef int _str_to_pj_str(object string, pj_str_t *pj_str) except -1:
#print('Convert %s (%s)' % (string, type(string)))
pj_str.ptr = PyBytes_AsString(string)
pj_str.slen = len(string)
cdef object _pj_str_to_bytes(pj_str_t pj_str):
return PyBytes_FromStringAndSize(pj_str.ptr, pj_str.slen)
cdef object _pj_str_to_str(pj_str_t pj_str):
return PyBytes_FromStringAndSize(pj_str.ptr, pj_str.slen).decode()
cdef object _pj_buf_len_to_str(object buf, int buf_len):
return PyBytes_FromStringAndSize(buf, buf_len)
cdef object _buf_to_str(object buf):
- return PyBytes_FromString(buf)
+ return PyBytes_FromString(buf).decode()
cdef object _str_as_str(object string):
return PyBytes_AsString(string)
cdef object _str_as_size(object string):
return PyBytes_Size(string)
cdef object _pj_status_to_str(int status):
cdef char buf[PJ_ERR_MSG_SIZE]
return _pj_str_to_str(pj_strerror(status, buf, PJ_ERR_MSG_SIZE))
cdef object _pj_status_to_def(int status):
return _re_pj_status_str_def.match(_pj_status_to_str(status)).group(1)
cdef dict _pjsip_param_to_dict(pjsip_param *param_list):
cdef pjsip_param *param
cdef dict retval = dict()
param = <pjsip_param *> (<pj_list *> param_list).next
while param != param_list:
if param.value.slen == 0:
retval[_pj_str_to_str(param.name)] = None
else:
retval[_pj_str_to_str(param.name)] = _pj_str_to_str(param.value)
param = <pjsip_param *> (<pj_list *> param).next
return retval
cdef int _dict_to_pjsip_param(object params, pjsip_param *param_list, pj_pool_t *pool):
cdef pjsip_param *param = NULL
for name, value in params.iteritems():
param = <pjsip_param *> pj_pool_alloc(pool, sizeof(pjsip_param))
if param == NULL:
return -1
_str_to_pj_str(name, &param.name)
if value is None:
param.value.slen = 0
else:
_str_to_pj_str(value, &param.value)
pj_list_insert_after(<pj_list *> param_list, <pj_list *> param)
return 0
cdef int _pjsip_msg_to_dict(pjsip_msg *msg, dict info_dict) except -1:
cdef pjsip_msg_body *body
cdef pjsip_hdr *header
cdef pjsip_generic_array_hdr *array_header
cdef pjsip_ctype_hdr *ctype_header
cdef pjsip_cseq_hdr *cseq_header
cdef char *buf
cdef int buf_len, i, status
headers = {}
header = <pjsip_hdr *> (<pj_list *> &msg.hdr).next
while header != &msg.hdr:
header_name = _pj_str_to_str(header.name)
header_data = None
multi_header = False
if header_name in ("Accept", "Allow", "Require", "Supported", "Unsupported", "Allow-Events"):
array_header = <pjsip_generic_array_hdr *> header
header_data = []
for i from 0 <= i < array_header.count:
pass
# TODO crash here
#header_data.append(_pj_str_to_str(array_header.values[i]))
elif header_name == "Contact":
multi_header = True
header_data = FrozenContactHeader_create(<pjsip_contact_hdr *> header)
elif header_name == "Content-Length":
header_data = (<pjsip_clen_hdr *> header).len
elif header_name == "Content-Type":
header_data = FrozenContentTypeHeader_create(<pjsip_ctype_hdr *> header)
elif header_name == "CSeq":
cseq_header = <pjsip_cseq_hdr *> header
hvalue = _pj_str_to_str(cseq_header.method.name)
header_data = (cseq_header.cseq, hvalue)
elif header_name in ("Expires", "Max-Forwards", "Min-Expires"):
header_data = (<pjsip_generic_int_hdr *> header).ivalue
elif header_name == "From":
header_data = FrozenFromHeader_create(<pjsip_fromto_hdr *> header)
elif header_name == "To":
header_data = FrozenToHeader_create(<pjsip_fromto_hdr *> header)
elif header_name == "Route":
multi_header = True
header_data = FrozenRouteHeader_create(<pjsip_routing_hdr *> header)
elif header_name == "Reason":
value = _pj_str_to_str((<pjsip_generic_string_hdr *>header).hvalue)
protocol, sep, params_str = value.partition(';')
params = frozendict([(name, value or None) for name, sep, value in [param.partition('=') for param in params_str.split(';')]])
header_data = FrozenReasonHeader(protocol, params)
elif header_name == "Record-Route":
multi_header = True
header_data = FrozenRecordRouteHeader_create(<pjsip_routing_hdr *> header)
elif header_name == "Retry-After":
header_data = FrozenRetryAfterHeader_create(<pjsip_retry_after_hdr *> header)
elif header_name == "Via":
multi_header = True
header_data = FrozenViaHeader_create(<pjsip_via_hdr *> header)
elif header_name == "Warning":
match = _re_warning_hdr.match(_pj_str_to_str((<pjsip_generic_string_hdr *>header).hvalue))
if match is not None:
warning_params = match.groupdict()
warning_params['code'] = int(warning_params['code'])
header_data = FrozenWarningHeader(**warning_params)
elif header_name == "Event":
header_data = FrozenEventHeader_create(<pjsip_event_hdr *> header)
elif header_name == "Subscription-State":
header_data = FrozenSubscriptionStateHeader_create(<pjsip_sub_state_hdr *> header)
elif header_name == "Refer-To":
header_data = FrozenReferToHeader_create(<pjsip_generic_string_hdr *> header)
elif header_name == "Subject":
header_data = FrozenSubjectHeader_create(<pjsip_generic_string_hdr *> header)
elif header_name == "Replaces":
header_data = FrozenReplacesHeader_create(<pjsip_replaces_hdr *> header)
# skip the following headers:
elif header_name not in ("Authorization", "Proxy-Authenticate", "Proxy-Authorization", "WWW-Authenticate"):
hvalue = (<pjsip_generic_string_hdr *> header).hvalue
header_value = _pj_str_to_str(hvalue)
header_data = FrozenHeader(header_name, header_value)
if header_data is not None:
if multi_header:
headers.setdefault(header_name, []).append(header_data)
else:
if header_name not in headers:
headers[header_name] = header_data
header = <pjsip_hdr *> (<pj_list *> header).next
info_dict["headers"] = headers
body = msg.body
if body == NULL:
info_dict["body"] = None
else:
status = pjsip_print_body(body, &buf, &buf_len)
if status != 0:
info_dict["body"] = None
else:
info_dict["body"] = _pj_buf_len_to_str(buf, buf_len).decode()
if msg.type == PJSIP_REQUEST_MSG:
info_dict["method"] = _pj_str_to_str(msg.line.req.method.name)
# You need to call pjsip_uri_get_uri on the request URI if the message is for transmitting,
# but it isn't required if message is one received. Otherwise, a seg fault occurs. Don't ask.
info_dict["request_uri"] = FrozenSIPURI_create(<pjsip_sip_uri*>pjsip_uri_get_uri(msg.line.req.uri))
else:
info_dict["code"] = msg.line.status.code
info_dict["reason"] = _pj_str_to_str(msg.line.status.reason)
return 0
cdef int _is_valid_ip(int af, object ip) except -1:
cdef char buf[16]
cdef pj_str_t src
cdef int status
_str_to_pj_str(ip, &src)
status = pj_inet_pton(af, &src, buf)
if status == 0:
return 1
else:
return 0
cdef int _get_ip_version(object ip) except -1:
if _is_valid_ip(pj_AF_INET(), ip):
return pj_AF_INET()
elif _is_valid_ip(pj_AF_INET6(), ip):
return pj_AF_INET()
else:
return 0
cdef int _add_headers_to_tdata(pjsip_tx_data *tdata, object headers) except -1:
cdef pj_str_t name_pj, value_pj
cdef pjsip_hdr *hdr
for header in headers:
hb = header.name.encode()
bb = header.body.encode()
_str_to_pj_str(hb, &name_pj)
_str_to_pj_str(bb, &value_pj)
hdr = <pjsip_hdr *> pjsip_generic_string_hdr_create(tdata.pool, &name_pj, &value_pj)
pjsip_msg_add_hdr(tdata.msg, hdr)
cdef int _remove_headers_from_tdata(pjsip_tx_data *tdata, object headers) except -1:
cdef pj_str_t header_name_pj
cdef pjsip_hdr *hdr
for header in headers:
_str_to_pj_str(header, &header_name_pj)
hdr = <pjsip_hdr *> pjsip_msg_find_remove_hdr_by_name(tdata.msg, &header_name_pj, NULL)
cdef int _BaseRouteHeader_to_pjsip_route_hdr(BaseIdentityHeader header, pjsip_route_hdr *pj_header, pj_pool_t *pool) except -1:
cdef pjsip_param *param
cdef pjsip_sip_uri *sip_uri
pjsip_route_hdr_init(NULL, <void *> pj_header)
sip_uri = <pjsip_sip_uri *> pj_pool_alloc(pool, sizeof(pjsip_sip_uri))
_BaseSIPURI_to_pjsip_sip_uri(header.uri, sip_uri, pool)
pj_header.name_addr.uri = <pjsip_uri *> sip_uri
if header.display_name:
_str_to_pj_str(header.display_name, &pj_header.name_addr.display)
_dict_to_pjsip_param(header.parameters, &pj_header.other_param, pool)
return 0
cdef int _BaseSIPURI_to_pjsip_sip_uri(BaseSIPURI uri, pjsip_sip_uri *pj_uri, pj_pool_t *pool) except -1:
cdef pjsip_param *param
pjsip_sip_uri_init(pj_uri, uri.secure)
if uri.user:
_str_to_pj_str(uri.user.encode(), &pj_uri.user)
if uri.password:
_str_to_pj_str(uri.password.encode(), &pj_uri.passwd)
if uri.host:
_str_to_pj_str(uri.host.encode(), &pj_uri.host)
if uri.port:
pj_uri.port = uri.port
for name, value in uri.parameters.iteritems():
#print('Parse parameter %s (%s): %s (%s)' % (name, type(name), value, type(value)))
if value is not None:
try:
int(value)
except ValueError:
value = value.encode()
name = name.encode()
if name == "lr":
pj_uri.lr_param = 1
elif name == "maddr":
_str_to_pj_str(value, &pj_uri.maddr_param)
elif name == "method":
_str_to_pj_str(value, &pj_uri.method_param)
elif name == "transport":
_str_to_pj_str(value, &pj_uri.transport_param)
elif name == "ttl":
pj_uri.ttl_param = int(value)
elif name == "user":
_str_to_pj_str(value, &pj_uri.user_param)
else:
param = <pjsip_param *> pj_pool_alloc(pool, sizeof(pjsip_param))
_str_to_pj_str(name, &param.name)
if value is None:
param.value.slen = 0
else:
_str_to_pj_str(value, &param.value)
pj_list_insert_after(<pj_list *> &pj_uri.other_param, <pj_list *> param)
_dict_to_pjsip_param(uri.headers, &pj_uri.header_param, pool)
return 0
def _get_device_name_encoding():
if sys.platform == 'win32':
encoding = 'mbcs'
elif sys.platform.startswith('linux2') and Version.parse(platform.release()) < Version(2,6,31):
encoding = 'latin1'
else:
encoding = 'utf-8'
return encoding
_device_name_encoding = _get_device_name_encoding()
def decode_device_name(device_name):
# ignore decoding errors, some systems (I'm looking at you, OSX), seem to misbehave
return device_name.decode(_device_name_encoding, 'ignore')
# globals
cdef object _re_pj_status_str_def = re.compile("^.*\((.*)\)$")
cdef object _re_warning_hdr = re.compile('(?P<code>[0-9]{3}) (?P<agent>.*?) "(?P<text>.*?)"')
sip_status_messages = SIPStatusMessages()

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 11:25 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3409121
Default Alt Text
(323 KB)

Event Timeline