Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F7232214
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
27 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/sipsimple/core.mediatransport.pxi b/sipsimple/core.mediatransport.pxi
index a762ecf9..9fb221ec 100644
--- a/sipsimple/core.mediatransport.pxi
+++ b/sipsimple/core.mediatransport.pxi
@@ -1,621 +1,623 @@
# Copyright (C) 2008-2009 AG Projects. See LICENSE for details.
#
# classes
cdef class RTPTransport:
cdef pjmedia_transport *_obj
cdef pjmedia_transport *_wrapped_transport
cdef pj_pool_t *_pool
cdef int _af
cdef object _local_rtp_addr
cdef readonly object remote_rtp_port_sdp
cdef readonly object remote_rtp_address_sdp
cdef readonly object state
cdef readonly object use_srtp
cdef readonly object srtp_forced
cdef readonly object use_ice
cdef readonly object ice_stun_address
cdef readonly object ice_stun_port
def __cinit__(self, *args, **kwargs):
cdef object pool_name = "RTPTransport_%d" % id(self)
cdef PJSIPUA ua = _get_ua()
self._af = pj_AF_INET()
self.state = "NULL"
self._pool = pjsip_endpt_create_pool(ua._pjsip_endpoint._obj, pool_name, 4096, 4096)
if self._pool == NULL:
raise SIPCoreError("Could not allocate memory pool")
def __init__(self, local_rtp_address=None, use_srtp=False, srtp_forced=False, use_ice=False,
ice_stun_address=None, ice_stun_port=PJ_STUN_PORT):
cdef PJSIPUA ua = _get_ua()
if self.state != "NULL":
raise SIPCoreError("RTPTransport.__init__() was already called")
if local_rtp_address is not None and not _is_valid_ip(self._af, local_rtp_address):
raise ValueError("Not a valid IPv4 address: %s" % local_rtp_address)
if ice_stun_address is not None and not _is_valid_ip(self._af, ice_stun_address):
raise ValueError("Not a valid IPv4 address: %s" % ice_stun_address)
self._local_rtp_addr = local_rtp_address
self.use_srtp = use_srtp
self.srtp_forced = srtp_forced
self.use_ice = use_ice
self.ice_stun_address = ice_stun_address
self.ice_stun_port = ice_stun_port
def __dealloc__(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
return
if self.state in ["LOCAL", "ESTABLISHED"]:
pjmedia_transport_media_stop(self._obj)
if self._obj != NULL:
pjmedia_transport_close(self._obj)
self._wrapped_transport = NULL
if self._wrapped_transport != NULL:
pjmedia_transport_close(self._wrapped_transport)
if self._pool != NULL:
pjsip_endpt_release_pool(ua._pjsip_endpoint._obj, self._pool)
cdef PJSIPUA _check_ua(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
return ua
except:
self.state = "INVALID"
self._obj = NULL
self._wrapped_transport = NULL
self._pool = NULL
return None
cdef int _get_info(self, pjmedia_transport_info *info) except -1:
cdef int status
pjmedia_transport_info_init(info)
status = pjmedia_transport_get_info(self._obj, info)
if status != 0:
raise PJSIPError("Could not get transport info", status)
return 0
property local_rtp_port:
def __get__(self):
cdef pjmedia_transport_info info
self._check_ua()
if self.state in ["NULL", "WAIT_STUN", "INVALID"]:
return None
self._get_info(&info)
if info.sock_info.rtp_addr_name.addr.sa_family != 0:
return pj_sockaddr_get_port(&info.sock_info.rtp_addr_name)
else:
return None
property local_rtp_address:
def __get__(self):
cdef pjmedia_transport_info info
cdef char buf[PJ_INET6_ADDRSTRLEN]
self._check_ua()
if self.state in ["NULL", "WAIT_STUN", "INVALID"]:
return self._local_rtp_addr
self._get_info(&info)
if pj_sockaddr_has_addr(&info.sock_info.rtp_addr_name):
return pj_sockaddr_print(&info.sock_info.rtp_addr_name, buf, PJ_INET6_ADDRSTRLEN, 0)
else:
return None
property remote_rtp_port_received:
def __get__(self):
cdef pjmedia_transport_info info
self._check_ua()
if self.state in ["NULL", "WAIT_STUN", "INVALID"]:
return None
self._get_info(&info)
if info.src_rtp_name.addr.sa_family != 0:
return pj_sockaddr_get_port(&info.src_rtp_name)
else:
return None
property remote_rtp_address_received:
def __get__(self):
cdef pjmedia_transport_info info
cdef char buf[PJ_INET6_ADDRSTRLEN]
self._check_ua()
if self.state in ["NULL", "WAIT_STUN", "INVALID"]:
return None
self._get_info(&info)
if pj_sockaddr_has_addr(&info.src_rtp_name):
return pj_sockaddr_print(&info.src_rtp_name, buf, PJ_INET6_ADDRSTRLEN, 0)
else:
return None
property srtp_active:
def __get__(self):
cdef pjmedia_transport_info info
cdef pjmedia_srtp_info *srtp_info
cdef int i
self._check_ua()
if self.state in ["NULL", "WAIT_STUN", "INVALID"]:
return False
self._get_info(&info)
for i from 0 <= i < info.specific_info_cnt:
if info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP:
srtp_info = <pjmedia_srtp_info *> info.spc_info[i].buffer
return bool(srtp_info.active)
return False
cdef int _update_local_sdp(self, SDPSession local_sdp, int sdp_index, pjmedia_sdp_session *remote_sdp) except -1:
cdef int status
if sdp_index < 0:
raise ValueError("sdp_index argument cannot be negative")
if sdp_index >= local_sdp._obj.media_count:
raise ValueError("sdp_index argument out of range")
status = pjmedia_transport_media_create(self._obj, self._pool, 0, remote_sdp, sdp_index)
if status != 0:
raise PJSIPError("Could not create media transport", status)
status = pjmedia_transport_encode_sdp(self._obj, self._pool, &local_sdp._obj, remote_sdp, sdp_index)
if status != 0:
raise PJSIPError("Could not update SDP for media transport", status)
# TODO: work the changes back into the local_sdp object, but we don't need to do that yet.
return 0
def set_LOCAL(self, SDPSession local_sdp, int sdp_index):
self._check_ua()
if local_sdp is None:
raise SIPCoreError("local_sdp argument cannot be None")
if self.state == "LOCAL":
return
if self.state != "INIT":
raise SIPCoreError('set_LOCAL can only be called in the "INIT" state, current state is "%s"' % self.state)
local_sdp._to_c()
self._update_local_sdp(local_sdp, sdp_index, NULL)
self.state = "LOCAL"
def set_ESTABLISHED(self, SDPSession local_sdp, SDPSession remote_sdp, int sdp_index):
cdef int status
self._check_ua()
if None in [local_sdp, remote_sdp]:
raise SIPCoreError("SDP arguments cannot be None")
if self.state == "ESTABLISHED":
return
if self.state not in ["INIT", "LOCAL"]:
raise SIPCoreError('set_ESTABLISHED can only be called in the "INIT" and "LOCAL" states, ' +
'current state is "%s"' % self.state)
local_sdp._to_c()
remote_sdp._to_c()
if self.state == "INIT":
self._update_local_sdp(local_sdp, sdp_index, &remote_sdp._obj)
status = pjmedia_transport_media_start(self._obj, self._pool, &local_sdp._obj, &remote_sdp._obj, sdp_index)
if status != 0:
raise PJSIPError("Could not start media transport", status)
if remote_sdp.media[sdp_index].connection is None:
if remote_sdp.connection is not None:
self.remote_rtp_address_sdp = remote_sdp.connection.address
else:
self.remote_rtp_address_sdp = remote_sdp.media[sdp_index].connection.address
self.remote_rtp_port_sdp = remote_sdp.media[sdp_index].port
self.state = "ESTABLISHED"
def set_INIT(self):
global _RTPTransport_stun_list, _ice_cb
cdef pj_str_t local_ip
cdef pj_str_t *local_ip_p = &local_ip
cdef pjmedia_srtp_setting srtp_setting
cdef pj_ice_strans_cfg ice_cfg
cdef int i
cdef int status
cdef PJSIPUA ua = self._check_ua()
if self.state == "INIT":
return
if self.state in ["LOCAL", "ESTABLISHED"]:
status = pjmedia_transport_media_stop(self._obj)
if status != 0:
raise PJSIPError("Could not stop media transport", status)
self.remote_rtp_address_sdp = None
self.remote_rtp_port_sdp = None
self.state = "INIT"
elif self.state == "NULL":
if self._local_rtp_addr is None:
local_ip_p = NULL
else:
_str_to_pj_str(self._local_rtp_addr, &local_ip)
if self.use_ice:
pj_ice_strans_cfg_default(&ice_cfg)
ice_cfg.af = self._af
pj_stun_config_init(&ice_cfg.stun_cfg, &ua._caching_pool._obj.factory, 0,
pjmedia_endpt_get_ioqueue(ua._pjmedia_endpoint._obj),
pjsip_endpt_get_timer_heap(ua._pjsip_endpoint._obj))
if self.ice_stun_address is not None:
_str_to_pj_str(self.ice_stun_address, &ice_cfg.stun.server)
ice_cfg.stun.port = self.ice_stun_port
# IIRC we can't choose the port for ICE
status = pj_sockaddr_init(ice_cfg.af, &ice_cfg.stun.cfg.bound_addr, local_ip_p, 0)
if status != 0:
raise PJSIPError("Could not init ICE bound address", status)
status = pjmedia_ice_create2(ua._pjmedia_endpoint._obj, NULL, 2, &ice_cfg, &_ice_cb, 0, &self._obj)
if status != 0:
raise PJSIPError("Could not create ICE media transport", status)
else:
status = PJ_EBUG
for i in xrange(ua._rtp_port_index, ua._rtp_port_index + ua._rtp_port_stop - ua._rtp_port_start, 2):
status = pjmedia_transport_udp_create3(ua._pjmedia_endpoint._obj, self._af, NULL, local_ip_p,
ua._rtp_port_start + i % (ua._rtp_port_stop -
ua._rtp_port_start),
0, &self._obj)
if status != PJ_ERRNO_START_SYS + EADDRINUSE:
ua._rtp_port_index = (i + 2) % (ua._rtp_port_stop - ua._rtp_port_start)
break
if status != 0:
raise PJSIPError("Could not create UDP/RTP media transport", status)
if self.use_srtp:
self._wrapped_transport = self._obj
self._obj = NULL
pjmedia_srtp_setting_default(&srtp_setting)
if self.srtp_forced:
srtp_setting.use = PJMEDIA_SRTP_MANDATORY
status = pjmedia_transport_srtp_create(ua._pjmedia_endpoint._obj,
self._wrapped_transport, &srtp_setting, &self._obj)
if status != 0:
pjmedia_transport_close(self._wrapped_transport)
self._wrapped_transport = NULL
raise PJSIPError("Could not create SRTP media transport", status)
if not self.use_ice or self.ice_stun_address is None:
self.state = "INIT"
_add_event("RTPTransportDidInitialize", dict(obj=self))
else:
self.state = "WAIT_STUN"
_RTPTransport_stun_list.append(self)
else:
raise SIPCoreError('set_INIT can only be called in the "NULL", "LOCAL" and "ESTABLISHED" states, ' +
'current state is "%s"' % self.state)
cdef class AudioTransport:
cdef pjmedia_stream *_obj
cdef pjmedia_stream_info _stream_info
cdef readonly RTPTransport transport
cdef pj_pool_t *_pool
cdef pjmedia_sdp_media *_local_media
cdef unsigned int _conf_slot
cdef readonly object direction
cdef int _is_started
cdef int _is_offer
cdef unsigned int _vad
cdef pj_timer_entry _timer
cdef int _timer_active
cdef unsigned int _packets_received
def __cinit__(self, *args, **kwargs):
cdef object pool_name = "AudioTransport_%d" % id(self)
cdef PJSIPUA ua = _get_ua()
self._pool = pjsip_endpt_create_pool(ua._pjsip_endpoint._obj, pool_name, 4096, 4096)
if self._pool == NULL:
raise SIPCoreError("Could not allocate memory pool")
pj_timer_entry_init(&self._timer, 0, <void *> self, _AudioTransport_cb_check_rtp)
def __init__(self, RTPTransport transport, SDPSession remote_sdp=None,
int sdp_index=0, enable_silence_detection=True, list codecs=None):
cdef pjmedia_transport_info info
cdef pjmedia_sdp_session *local_sdp_c
cdef SDPSession local_sdp
cdef list global_codecs
cdef int status
cdef PJSIPUA ua = _get_ua()
if self.transport is not None:
raise SIPCoreError("AudioTransport.__init__() was already called")
if transport is None:
raise ValueError("transport argument cannot be None")
if sdp_index < 0:
raise ValueError("sdp_index argument cannot be negative")
if transport.state != "INIT":
raise SIPCoreError('RTPTransport object provided is not in the "INIT" state, but in the "%s" state' %
transport.state)
self._vad = int(bool(enable_silence_detection))
self.transport = transport
transport._get_info(&info)
if codecs is not None:
global_codecs = ua._pjmedia_endpoint._get_codecs()
try:
if codecs is not None:
ua._pjmedia_endpoint._set_codecs(codecs)
status = pjmedia_endpt_create_sdp(ua._pjmedia_endpoint._obj, self._pool, 1, &info.sock_info, &local_sdp_c)
if status != 0:
raise PJSIPError("Could not generate SDP for audio session", status)
finally:
if codecs is not None:
ua._pjmedia_endpoint._set_codecs(global_codecs)
local_sdp = _make_SDPSession(local_sdp_c)
if remote_sdp is None:
self._is_offer = 1
self.transport.set_LOCAL(local_sdp, 0)
else:
self._is_offer = 0
if sdp_index != 0:
local_sdp.media = (sdp_index+1) * local_sdp.media
self.transport.set_ESTABLISHED(local_sdp, remote_sdp, sdp_index)
self._local_media = pjmedia_sdp_media_clone(self._pool, local_sdp._obj.media[sdp_index])
def __dealloc__(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
return
if self._obj != NULL:
self.stop()
if self._pool != NULL:
pjsip_endpt_release_pool(ua._pjsip_endpoint._obj, self._pool)
cdef PJSIPUA _check_ua(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
return ua
except:
self._obj = NULL
self._pool = NULL
return None
property is_active:
def __get__(self):
self._check_ua()
return bool(self._obj != NULL)
property is_started:
def __get__(self):
return bool(self._is_started)
property codec:
def __get__(self):
self._check_ua()
if self._obj == NULL:
return None
else:
return _pj_str_to_str(self._stream_info.fmt.encoding_name)
property sample_rate:
def __get__(self):
self._check_ua()
if self._obj == NULL:
return None
else:
return self._stream_info.fmt.clock_rate
property enable_silence_detection:
def __get__(self):
return bool(self._vad)
def get_local_media(self, is_offer, direction="sendrecv"):
cdef SDPAttribute attr
cdef SDPMedia local_media
cdef object direction_attr
if is_offer and direction not in ["sendrecv", "sendonly", "recvonly", "inactive"]:
raise SIPCoreError("Unknown direction: %s" % direction)
local_media = _make_SDPMedia(self._local_media)
local_media.attributes = [<object> attr for attr in local_media.attributes if attr.name not in ["sendrecv",
"sendonly",
"recvonly",
"inactive"]]
if is_offer:
direction_attr = direction
else:
if self.direction is None or "recv" in self.direction:
direction_attr = "sendrecv"
else:
direction_attr = "sendonly"
local_media.attributes.append(SDPAttribute(direction_attr, ""))
return local_media
def start(self, SDPSession local_sdp, SDPSession remote_sdp, int sdp_index,
int no_media_timeout=10, int media_check_interval=30):
cdef pjmedia_port *media_port
cdef pj_time_val no_media_pj
cdef int status
cdef object desired_state
cdef PJSIPUA ua = _get_ua()
if self._is_started:
raise SIPCoreError("This AudioTransport was already started once")
desired_state = ("LOCAL" if self._is_offer else "ESTABLISHED")
if self.transport.state != desired_state:
raise SIPCoreError('RTPTransport object provided is not in the "%s" state, but in the "%s" state' %
(desired_state, self.transport.state))
if None in [local_sdp, remote_sdp]:
raise ValueError("SDP arguments cannot be None")
if sdp_index < 0:
raise ValueError("sdp_index argument cannot be negative")
if local_sdp.media[sdp_index].port == 0 or remote_sdp.media[sdp_index].port == 0:
raise SIPCoreError("Cannot start a rejected audio stream")
- if no_media_timeout <= 0:
- raise ValueError("no_media_timeout value cannot be negative or 0")
- if media_check_interval <= 0:
- raise ValueError("media_check_interval value cannot be negative or 0")
+ if no_media_timeout < 0:
+ raise ValueError("no_media_timeout value cannot be negative")
+ if media_check_interval < 0:
+ raise ValueError("media_check_interval value cannot be negative")
no_media_pj.sec = no_media_timeout
no_media_pj.msec = 0
if self.transport.state == "LOCAL":
self.transport.set_ESTABLISHED(local_sdp, remote_sdp, sdp_index)
else:
local_sdp._to_c()
remote_sdp._to_c()
status = pjmedia_stream_info_from_sdp(&self._stream_info, self._pool, ua._pjmedia_endpoint._obj,
&local_sdp._obj, &remote_sdp._obj, sdp_index)
if status != 0:
raise PJSIPError("Could not parse SDP for audio session", status)
if self._stream_info.param == NULL:
raise SIPCoreError("Could not parse SDP for audio session")
self._stream_info.param.setting.vad = self._vad
status = pjmedia_stream_create(ua._pjmedia_endpoint._obj, self._pool, &self._stream_info,
self.transport._obj, NULL, &self._obj)
if status != 0:
raise PJSIPError("Could not initialize RTP for audio session", status)
status = pjmedia_stream_set_dtmf_callback(self._obj, _AudioTransport_cb_dtmf, <void *> self)
if status != 0:
pjmedia_stream_destroy(self._obj)
self._obj = NULL
raise PJSIPError("Could not set DTMF callback for audio session", status)
status = pjmedia_stream_start(self._obj)
if status != 0:
pjmedia_stream_destroy(self._obj)
self._obj = NULL
raise PJSIPError("Could not start RTP for audio session", status)
status = pjmedia_stream_get_port(self._obj, &media_port)
if status != 0:
pjmedia_stream_destroy(self._obj)
self._obj = NULL
raise PJSIPError("Could not get audio port for audio session", status)
status = pjmedia_conf_add_port(ua._conf_bridge._obj, self._pool, media_port, NULL, &self._conf_slot)
if status != 0:
pjmedia_stream_destroy(self._obj)
self._obj = NULL
raise PJSIPError("Could not connect audio session to conference bridge", status)
self.direction = "sendrecv"
self.update_direction(local_sdp.media[sdp_index].get_direction())
self._local_media = pjmedia_sdp_media_clone(self._pool, local_sdp._obj.media[sdp_index])
self._is_started = 1
- self._timer.id = media_check_interval
- status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &no_media_pj)
- if status == 0:
- self._timer_active = 1
+ if no_media_pj.sec > 0:
+ self._timer.id = media_check_interval
+ status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &no_media_pj)
+ if status == 0:
+ self._timer_active = 1
def stop(self):
cdef PJSIPUA ua = self._check_ua()
if self._timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
if self._obj == NULL:
return
ua._conf_bridge._disconnect_slot(self._conf_slot)
pjmedia_conf_remove_port(ua._conf_bridge._obj, self._conf_slot)
pjmedia_stream_destroy(self._obj)
self._obj = NULL
self.transport.set_INIT()
def update_direction(self, direction):
cdef int status1 = 0
cdef int status2 = 0
self._check_ua()
if self._obj == NULL:
raise SIPCoreError("Stream is not active")
if direction not in ["sendrecv", "sendonly", "recvonly", "inactive"]:
raise SIPCoreError("Unknown direction: %s" % direction)
if direction == self.direction:
return
if "send" in self.direction:
if "send" not in direction:
status1 = pjmedia_stream_pause(self._obj, PJMEDIA_DIR_ENCODING)
else:
if "send" in direction:
status1 = pjmedia_stream_resume(self._obj, PJMEDIA_DIR_ENCODING)
if "recv" in self.direction:
if "recv" not in direction:
status2 = pjmedia_stream_pause(self._obj, PJMEDIA_DIR_DECODING)
else:
if "recv" in direction:
status2 = pjmedia_stream_resume(self._obj, PJMEDIA_DIR_DECODING)
self.direction = direction
if status1 != 0:
raise SIPCoreError("Could not pause or resume encoding: %s" % _pj_status_to_str(status1))
if status2 != 0:
raise SIPCoreError("Could not pause or resume decoding: %s" % _pj_status_to_str(status2))
def send_dtmf(self, digit):
cdef pj_str_t digit_pj
cdef int status
cdef PJSIPUA ua = self._check_ua()
if self._obj == NULL:
raise SIPCoreError("Stream is not active")
if len(digit) != 1 or digit not in "0123456789*#ABCD":
raise SIPCoreError("Not a valid DTMF digit: %s" % digit)
_str_to_pj_str(digit, &digit_pj)
status = pjmedia_stream_dial_dtmf(self._obj, &digit_pj)
if status != 0:
raise PJSIPError("Could not send DTMF digit on audio stream", status)
ua._conf_bridge._playback_dtmf(ord(digit))
# callback functions
cdef void _RTPTransport_cb_ice_complete(pjmedia_transport *tp, pj_ice_strans_op op, int status) with gil:
global _RTPTransport_stun_list
cdef RTPTransport rtp_transport
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
if op != PJ_ICE_STRANS_OP_INIT:
return
for rtp_transport in _RTPTransport_stun_list:
if ((rtp_transport._wrapped_transport == NULL and rtp_transport._obj == tp) or
(rtp_transport._wrapped_transport != NULL and rtp_transport._wrapped_transport == tp)):
if status == 0:
rtp_transport.state = "INIT"
else:
rtp_transport.state = "INVALID"
if status == 0:
_add_event("RTPTransportDidInitialize", dict(obj=rtp_transport))
else:
_add_event("RTPTransportDidFail", dict(obj=rtp_transport, reason=_pj_status_to_str(status)))
_RTPTransport_stun_list.remove(rtp_transport)
return
except:
ua._handle_exception(1)
cdef void _AudioTransport_cb_dtmf(pjmedia_stream *stream, void *user_data, int digit) with gil:
cdef AudioTransport audio_stream = <object> user_data
cdef PJSIPUA ua
try:
ua = _get_ua()
except:
return
try:
_add_event("RTPAudioStreamGotDTMF", dict(obj=audio_stream, digit=chr(digit)))
try:
ua._conf_bridge._playback_dtmf(digit)
except:
ua._handle_exception(0)
except:
ua._handle_exception(1)
cdef void _AudioTransport_cb_check_rtp(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) with gil:
cdef PJSIPUA ua
cdef AudioTransport audio_transport
cdef pjmedia_rtcp_stat stat
cdef pj_time_val no_media_pj
cdef int status
try:
ua = _get_ua()
except:
return
try:
if entry.user_data != NULL:
audio_transport = <object> entry.user_data
audio_transport._timer_active = 0
status = pjmedia_stream_get_stat(audio_transport._obj, &stat)
if status == 0:
if audio_transport._packets_received == stat.rx.pkt and "recv" not in audio_transport.direction:
_add_event("RTPAudioTransportDidNotGetRTP", dict(obj=audio_transport, got_any=(stat.rx.pkt != 0)))
audio_transport._packets_received = stat.rx.pkt
no_media_pj.sec = entry.id
no_media_pj.msec = 0
- status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, entry, &no_media_pj)
- if status == 0:
- audio_transport._timer_active = 1
+ if no_media_pj.sec > 0:
+ status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, entry, &no_media_pj)
+ if status == 0:
+ audio_transport._timer_active = 1
except:
ua._handle_exception(1)
# globals
cdef pjmedia_ice_cb _ice_cb
_ice_cb.on_ice_complete = _RTPTransport_cb_ice_complete
_RTPTransport_stun_list = []
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Dec 28, 7:30 PM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3454347
Default Alt Text
(27 KB)
Attached To
Mode
rPYNSIPSIMPLE python3-sipsimple
Attached
Detach File
Event Timeline
Log In to Comment