def send_invite(self, 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_dialog **dialog_address
cdef pjsip_inv_session **invite_session_address
cdef pjsip_route_hdr *route_set
cdef pjsip_tx_data *tdata
cdef PJSIPUA ua
cdef PJSTR contact_header_str
cdef PJSTR from_header_str
cdef PJSTR to_header_str
cdef PJSTR target_str
ua = _get_ua()
with nogil:
status = pj_mutex_lock(lock)
if status != 0:
raise PJSIPError("failed to acquire lock", status)
try:
dialog_address = &self._dialog
invite_session_address = &self._invite_session
route_set = <pjsip_route_hdr *> &self._route_set
if self.state != 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")
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 pj_mutex_t *lock = self._lock
cdef pj_str_t reason_str
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 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 != "received_proposal":
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
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:
raise PJSIPError("Could not send %d response" % code, status)
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
# the only reason for which this error can be thrown is if invitation.send_response was called after the INVITE session was cancelled by the remote party
# the only reason for which this error can be thrown is if invitation.send_response was called after the INVITE session was cancelled by the remote party
hold_supported_streams = (stream for stream in self.streams if stream.hold_supported)
notification_center.post_notification('SIPSessionDidChangeHoldState', self, TimestampedNotificationData(originator='local', on_hold=True, partial=any(not stream.on_hold_by_local for stream in hold_supported_streams)))
self._invitation.send_response(488, extra_headers=[WarningHeader(399, engine.user_agent, 'Both removing AND adding a media stream is currently not supported')])
self._invitation.send_response(488, extra_headers=[WarningHeader(399, engine.user_agent, 'Changing the codec of an audio stream is currently not supported')])