diff options
author | Benny Prijono <bennylp@teluu.com> | 2008-07-21 18:20:57 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2008-07-21 18:20:57 +0000 |
commit | f50466cf0839b9abd6beb12576e83b3a78b9013c (patch) | |
tree | 3da37da741d3cba8b6faeb0d0b3cb379358b249c /pjsip-apps/src/python/pjsua.py | |
parent | d96688e27a0e7d8c06ac3e399718a217daf6994e (diff) |
Major modifications in Python module and pjsua.py wrapper:
- replaced call/acc/buddy dictionaries with user data attachment
- recommended to install callback when creating the object, to
prevent missing some events
- fixed circular references by using weakref
- protect access to pjsua with mutex; found out that without this
there will be deadlock in Python
- fixed memory leaks in the _pjsua.c module (objects reference
counter not properly maintained)
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2163 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip-apps/src/python/pjsua.py')
-rw-r--r-- | pjsip-apps/src/python/pjsua.py | 401 |
1 files changed, 271 insertions, 130 deletions
diff --git a/pjsip-apps/src/python/pjsua.py b/pjsip-apps/src/python/pjsua.py index 96dd0e17..0eea110f 100644 --- a/pjsip-apps/src/python/pjsua.py +++ b/pjsip-apps/src/python/pjsua.py @@ -150,6 +150,8 @@ Account's send_pager() method. """ import _pjsua import thread +import threading +import weakref class Error: """Error exception class. @@ -623,16 +625,21 @@ class Transport: _obj_name = "" def __init__(self, lib, id): - self._lib = lib + self._lib = weakref.proxy(lib) self._id = id - self._obj_name = "Transport " + self.info().description + self._obj_name = "{Transport " + self.info().description + "}" + _Trace((self, 'created')) + def __del__(self): + _Trace((self, 'destroyed')) + def __str__(self): return self._obj_name def info(self): """Get TransportInfo. """ + lck = self._lib.auto_lock() ti = _pjsua.transport_get_info(self._id) if not ti: self._lib._err_check("info()", self, -1, "Invalid transport") @@ -640,11 +647,13 @@ class Transport: def enable(self): """Enable this transport.""" + lck = self._lib.auto_lock() err = _pjsua.transport_set_enable(self._id, True) self._lib._err_check("enable()", self, err) def disable(self): """Disable this transport.""" + lck = self._lib.auto_lock() err = _pjsua.transport_set_enable(self._id, 0) self._lib._err_check("disable()", self, err) @@ -654,6 +663,7 @@ class Transport: Keyword argument: force -- force deletion of this transport (not recommended). """ + lck = self._lib.auto_lock() err = _pjsua.transport_close(self._id, force) self._lib._err_check("close()", self, err) @@ -975,8 +985,17 @@ class AccountCallback: """ account = None - def __init__(self, account): - self.account = account + def __init__(self, account=None): + self._set_account(account) + + def __del__(self): + pass + + def _set_account(self, account): + if account: + self.account = weakref.proxy(account) + else: + self.account = None def on_reg_state(self): """Notification that the registration status has changed. @@ -994,7 +1013,7 @@ class AccountCallback: """ call.hangup() - def on_incoming_subscribe(self, buddy, from_uri, pres_obj): + def on_incoming_subscribe(self, buddy, from_uri, contact_uri, pres_obj): """Notification when incoming SUBSCRIBE request is received. Application may use this callback to authorize the incoming @@ -1098,22 +1117,28 @@ class Account: _cb = AccountCallback(None) _obj_name = "" - def __init__(self, lib, id): + def __init__(self, lib, id, cb=None): """Construct this class. This is normally called by Lib class and not by application. Keyword arguments: lib -- the Lib instance. id -- the pjsua account ID. + cb -- AccountCallback instance to receive events from this Account. + If callback is not specified here, it must be set later + using set_callback(). """ - self._cb = AccountCallback(self) self._id = id - self._lib = lib - self._lib._associate_account(self._id, self) - self._obj_name = "Account " + self.info().uri + self._lib = weakref.ref(lib) + self._obj_name = "{Account " + self.info().uri + "}" + self.set_callback(cb) + _pjsua.acc_set_user_data(self._id, self) + _Trace((self, 'created')) def __del__(self): - self._lib._disassociate_account(self._id, self) + if self._id != -1: + _pjsua.acc_set_user_data(self._id, 0) + _Trace((self, 'destroyed')) def __str__(self): return self._obj_name @@ -1121,9 +1146,10 @@ class Account: def info(self): """Retrieve AccountInfo for this account. """ + lck = self._lib().auto_lock() ai = _pjsua.acc_get_info(self._id) if ai==None: - self._lib._err_check("info()", self, -1, "Invalid account") + self._lib()._err_check("info()", self, -1, "Invalid account") return AccountInfo(ai) def is_valid(self): @@ -1131,6 +1157,7 @@ class Account: Check if this account is still valid. """ + lck = self._lib().auto_lock() return _pjsua.acc_is_valid(self._id) def set_callback(self, cb): @@ -1144,19 +1171,22 @@ class Account: self._cb = cb else: self._cb = AccountCallback(self) + self._cb._set_account(self) def set_default(self): """ Set this account as default account to send outgoing requests and as the account to receive incoming requests when more exact matching criteria fails. """ + lck = self._lib().auto_lock() err = _pjsua.acc_set_default(self._id) - self._lib._err_check("set_default()", self, err) + self._lib()._err_check("set_default()", self, err) def is_default(self): """ Check if this account is the default account. """ + lck = self._lib().auto_lock() def_id = _pjsua.acc_get_default() return self.is_valid() and def_id==self._id @@ -1164,8 +1194,12 @@ class Account: """ Delete this account. """ + lck = self._lib().auto_lock() + err = _pjsua.acc_set_user_data(self._id, 0) + self._lib()._err_check("delete()", self, err) err = _pjsua.acc_del(self._id) - self._lib._err_check("delete()", self, err) + self._lib()._err_check("delete()", self, err) + self._id = -1 def set_basic_status(self, is_online): """ Set basic presence status of this account. @@ -1174,8 +1208,9 @@ class Account: is_online -- boolean to indicate basic presence availability. """ + lck = self._lib().auto_lock() err = _pjsua.acc_set_online_status(self._id, is_online) - self._lib._err_check("set_basic_status()", self, err) + self._lib()._err_check("set_basic_status()", self, err) def set_presence_status(self, is_online, activity=PresenceActivity.UNKNOWN, @@ -1190,9 +1225,10 @@ class Account: rpid_id -- optional string to be placed as RPID ID. """ + lck = self._lib().auto_lock() err = _pjsua.acc_set_online_status2(self._id, is_online, activity, pres_text, rpid_id) - self._lib._err_check("set_presence_status()", self, err) + self._lib()._err_check("set_presence_status()", self, err) def set_registration(self, renew): """Manually renew registration or unregister from the server. @@ -1202,18 +1238,9 @@ class Account: Setting this value for False will trigger unregistration. """ + lck = self._lib().auto_lock() err = _pjsua.acc_set_registration(self._id, renew) - self._lib._err_check("set_registration()", self, err) - - def has_registration(self): - """Returns True if registration is active for this account. - - """ - acc_info = _pjsua.acc_get_info(self._id) - if not acc_info: - self._lib._err_check("has_registration()", self, -1, - "invalid account") - return acc_info.has_registration + self._lib()._err_check("set_registration()", self, err) def set_transport(self, transport): """Set this account to only use the specified transport to send @@ -1223,38 +1250,54 @@ class Account: transport -- Transport object. """ + lck = self._lib().auto_lock() err = _pjsua.acc_set_transport(self._id, transport._id) - self._lib._err_check("set_transport()", self, err) + self._lib()._err_check("set_transport()", self, err) - def make_call(self, dst_uri, hdr_list=None): + def make_call(self, dst_uri, cb=None, hdr_list=None): """Make outgoing call to the specified URI. Keyword arguments: dst_uri -- Destination SIP URI. + cb -- CallCallback instance to be installed to the newly + created Call object. If this CallCallback is not + specified (i.e. None is given), it must be installed + later using call.set_callback(). hdr_list -- Optional list of headers to be sent with outgoing INVITE + Return: + Call instance. """ + lck = self._lib().auto_lock() + call = Call(self._lib(), -1, cb) err, cid = _pjsua.call_make_call(self._id, dst_uri, 0, - 0, Lib._create_msg_data(hdr_list)) - self._lib._err_check("make_call()", self, err) - return Call(self._lib, cid) + call, Lib._create_msg_data(hdr_list)) + self._lib()._err_check("make_call()", self, err) + call.attach_to_id(cid) + return call - def add_buddy(self, uri): + def add_buddy(self, uri, cb=None): """Add new buddy. Keyword argument: - uri -- SIP URI of the buddy + uri -- SIP URI of the buddy + cb -- BuddyCallback instance to be installed to the newly + created Buddy object. If this callback is not specified + (i.e. None is given), it must be installed later using + buddy.set_callback(). Return: Buddy object """ + lck = self._lib().auto_lock() buddy_cfg = _pjsua.buddy_config_default() buddy_cfg.uri = uri buddy_cfg.subscribe = False err, buddy_id = _pjsua.buddy_add(buddy_cfg) - self._lib._err_check("add_buddy()", self, err) - return Buddy(self._lib, buddy_id, self) + self._lib()._err_check("add_buddy()", self, err) + buddy = Buddy(self._lib(), buddy_id, self, cb) + return buddy def pres_notify(self, pres_obj, state, reason="", hdr_list=None): """Send NOTIFY to inform account presence status or to terminate @@ -1267,6 +1310,7 @@ class Account: reason -- Optional reason phrase. hdr_list -- Optional header list. """ + lck = self._lib().auto_lock() _pjsua.acc_pres_notify(self._id, pres_obj, state, reason, Lib._create_msg_data(hdr_list)) @@ -1283,8 +1327,17 @@ class CallCallback: """ call = None - def __init__(self, call): - self.call = call + def __init__(self, call=None): + self._set_call(call) + + def __del__(self): + pass + + def _set_call(self, call): + if call: + self.call = weakref.proxy(call) + else: + self.call = None def on_state(self): """Notification that the call's state has changed. @@ -1468,8 +1521,8 @@ class CallInfo: self.media_state = ci.media_status self.media_dir = ci.media_dir self.conf_slot = ci.conf_slot - self.call_time = ci.connect_duration.sec - self.total_time = ci.total_duration.sec + self.call_time = ci.connect_duration / 1000 + self.total_time = ci.total_duration / 1000 class Call: @@ -1483,19 +1536,31 @@ class Call: _lib = None _obj_name = "" - def __init__(self, lib, call_id): - self._cb = CallCallback(self) - self._id = call_id - self._lib = lib - self._lib._associate_call(call_id, self) - self._obj_name = "Call " + self.info().remote_uri + def __init__(self, lib, call_id, cb=None): + self._lib = weakref.ref(lib) + self.set_callback(cb) + self.attach_to_id(call_id) + _Trace((self, 'created')) def __del__(self): - self._lib._disassociate_call(self._id, self) + if self._id != -1: + _pjsua.call_set_user_data(self._id, 0) + _Trace((self, 'destroyed')) def __str__(self): return self._obj_name + def attach_to_id(self, call_id): + lck = self._lib().auto_lock() + if self._id != -1: + _pjsua.call_set_user_data(self._id, 0) + self._id = call_id + if self._id != -1: + _pjsua.call_set_user_data(self._id, self) + self._obj_name = "{Call " + self.info().remote_uri + "}" + else: + self._obj_name = "{Call object}" + def set_callback(self, cb): """ Set callback object to retrieve event notifications from this call. @@ -1507,26 +1572,31 @@ class Call: self._cb = cb else: self._cb = CallCallback(self) + self._cb._set_call(self) def info(self): """ Get the CallInfo. """ + lck = self._lib().auto_lock() ci = _pjsua.call_get_info(self._id) if not ci: - self._lib._err_check("info", self, -1, "Invalid call") - return CallInfo(self._lib, ci) + self._lib()._err_check("info", self, -1, "Invalid call") + call_info = CallInfo(self._lib(), ci) + return call_info def is_valid(self): """ Check if this call is still valid. """ + lck = self._lib().auto_lock() return _pjsua.call_is_active(self._id) def dump_status(self, with_media=True, indent="", max_len=1024): """ Dump the call status. """ + lck = self._lib().auto_lock() return _pjsua.call_dump(self._id, with_media, max_len, indent) def answer(self, code=200, reason="", hdr_list=None): @@ -1541,9 +1611,10 @@ class Call: INVITE response. """ + lck = self._lib().auto_lock() err = _pjsua.call_answer(self._id, code, reason, Lib._create_msg_data(hdr_list)) - self._lib._err_check("answer()", self, err) + self._lib()._err_check("answer()", self, err) def hangup(self, code=603, reason="", hdr_list=None): """ @@ -1557,9 +1628,10 @@ class Call: message. """ + lck = self._lib().auto_lock() err = _pjsua.call_hangup(self._id, code, reason, Lib._create_msg_data(hdr_list)) - self._lib._err_check("hangup()", self, err) + self._lib()._err_check("hangup()", self, err) def hold(self, hdr_list=None): """ @@ -1569,8 +1641,9 @@ class Call: hdr_list -- Optional list of headers to be sent with the message. """ + lck = self._lib().auto_lock() err = _pjsua.call_set_hold(self._id, Lib._create_msg_data(hdr_list)) - self._lib._err_check("hold()", self, err) + self._lib()._err_check("hold()", self, err) def unhold(self, hdr_list=None): """ @@ -1581,9 +1654,10 @@ class Call: message. """ + lck = self._lib().auto_lock() err = _pjsua.call_reinvite(self._id, True, Lib._create_msg_data(hdr_list)) - self._lib._err_check("unhold()", self, err) + self._lib()._err_check("unhold()", self, err) def reinvite(self, hdr_list=None): """ @@ -1594,9 +1668,10 @@ class Call: message. """ + lck = self._lib().auto_lock() err = _pjsua.call_reinvite(self._id, True, Lib._create_msg_data(hdr_list)) - self._lib._err_check("reinvite()", self, err) + self._lib()._err_check("reinvite()", self, err) def update(self, hdr_list=None, options=0): """ @@ -1608,9 +1683,10 @@ class Call: options -- Must be zero for now. """ + lck = self._lib().auto_lock() err = _pjsua.call_update(self._id, options, Lib._create_msg_data(hdr_list)) - self._lib._err_check("update()", self, err) + self._lib()._err_check("update()", self, err) def transfer(self, dest_uri, hdr_list=None): """ @@ -1622,9 +1698,10 @@ class Call: message. """ + lck = self._lib().auto_lock() err = _pjsua.call_xfer(self._id, dest_uri, Lib._create_msg_data(hdr_list)) - self._lib._err_check("transfer()", self, err) + self._lib()._err_check("transfer()", self, err) def transfer_to_call(self, call, hdr_list=None, options=0): """ @@ -1637,9 +1714,10 @@ class Call: options -- Must be zero for now. """ + lck = self._lib().auto_lock() err = _pjsua.call_xfer_replaces(self._id, call._id, options, Lib._create_msg_data(hdr_list)) - self._lib._err_check("transfer_to_call()", self, err) + self._lib()._err_check("transfer_to_call()", self, err) def dial_dtmf(self, digits): """ @@ -1649,8 +1727,9 @@ class Call: digits -- DTMF digit string. """ + lck = self._lib().auto_lock() err = _pjsua.call_dial_dtmf(self._id, digits) - self._lib._err_check("dial_dtmf()", self, err) + self._lib()._err_check("dial_dtmf()", self, err) def send_request(self, method, hdr_list=None, content_type=None, body=None): @@ -1669,6 +1748,7 @@ class Call: body -- Optional SIP message body. """ + lck = self._lib().auto_lock() if hdr_list and body: msg_data = _pjsua.Msg_Data() if hdr_list: @@ -1681,7 +1761,7 @@ class Call: msg_data = None err = _pjsua.call_send_request(self._id, method, msg_data) - self._lib._err_check("send_request()", self, err) + self._lib()._err_check("send_request()", self, err) class BuddyInfo: @@ -1736,8 +1816,14 @@ class BuddyCallback: """ buddy = None - def __init__(self, buddy): - self.buddy = buddy + def __init__(self, buddy=None): + self._set_buddy(buddy) + + def _set_buddy(self, buddy): + if buddy: + self.buddy = weakref.proxy(buddy) + else: + self.buddy = None def on_state(self): """ @@ -1793,16 +1879,19 @@ class Buddy: _obj_name = "" _acc = None - def __init__(self, lib, id, account): - self._cb = BuddyCallback(self) - self._lib = lib + def __init__(self, lib, id, account, cb): self._id = id - self._acc = account - lib._associate_buddy(self._id, self) - self._obj_name = "Buddy " + self.info().uri + self._lib = weakref.ref(lib) + self._acc = weakref.ref(account) + self._obj_name = "{Buddy " + self.info().uri + "}" + self.set_callback(cb) + _pjsua.buddy_set_user_data(self._id, self) + _Trace((self, 'created')) def __del__(self): - self._lib._disassociate_buddy(self) + if self._id != -1: + _pjsua.buddy_set_user_data(self._id, 0) + _Trace((self, 'destroyed')) def __str__(self): return self._obj_name @@ -1811,6 +1900,7 @@ class Buddy: """ Get buddy info as BuddyInfo. """ + lck = self._lib().auto_lock() return BuddyInfo(_pjsua.buddy_get_info(self._id)) def set_callback(self, cb): @@ -1823,27 +1913,33 @@ class Buddy: self._cb = cb else: self._cb = BuddyCallback(self) + self._cb._set_buddy(self) def subscribe(self): """ Subscribe to buddy's presence status notification. """ + lck = self._lib().auto_lock() err = _pjsua.buddy_subscribe_pres(self._id, True) - self._lib._err_check("subscribe()", self, err) + self._lib()._err_check("subscribe()", self, err) def unsubscribe(self): """ Unsubscribe from buddy's presence status notification. """ + lck = self._lib().auto_lock() err = _pjsua.buddy_subscribe_pres(self._id, False) - self._lib._err_check("unsubscribe()", self, err) + self._lib()._err_check("unsubscribe()", self, err) def delete(self): """ Remove this buddy from the buddy list. """ + lck = self._lib().auto_lock() + if self._id != -1: + _pjsua.buddy_set_user_data(self._id, 0) err = _pjsua.buddy_del(self._id) - self._lib._err_check("delete()", self, err) + self._lib()._err_check("delete()", self, err) def send_pager(self, text, im_id=0, content_type="text/plain", \ hdr_list=None): @@ -1859,11 +1955,12 @@ class Buddy: request. """ - err = _pjsua.im_send(self._acc._id, self.info().uri, \ + lck = self._lib().auto_lock() + err = _pjsua.im_send(self._acc()._id, self.info().uri, \ content_type, text, \ Lib._create_msg_data(hdr_list), \ im_id) - self._lib._err_check("send_pager()", self, err) + self._lib()._err_check("send_pager()", self, err) def send_typing_ind(self, is_typing=True, hdr_list=None): """Send typing indication to remote buddy. @@ -1874,9 +1971,10 @@ class Buddy: request. """ - err = _pjsua.im_typing(self._acc._id, self.info().uri, \ + lck = self._lib().auto_lock() + err = _pjsua.im_typing(self._acc()._id, self.info().uri, \ is_typing, Lib._create_msg_data(hdr_list)) - self._lib._err_check("send_typing_ind()", self, err) + self._lib()._err_check("send_typing_ind()", self, err) @@ -1981,32 +2079,43 @@ class CodecParameter: return self._codec_param +# Library mutex +class _LibMutex: + def __init__(self, lck): + self._lck = lck + self._lck.acquire() + #print 'lck acquire' + + def __del__(self): + self._lck.release() + #print 'lck release' + + # PJSUA Library _lib = None class Lib: """Library instance. """ - call = {} - account = {} - buddy = {} - buddy_by_uri = {} - buddy_by_contact = {} _quit = False _has_thread = False + _lock = None def __init__(self): global _lib if _lib: raise Error("__init()__", None, -1, "Library instance already exist") - + + self._lock = threading.RLock() err = _pjsua.create() self._err_check("_pjsua.create()", None, err) _lib = self def __del__(self): _pjsua.destroy() + del self._lock + print 'Lib destroyed' def __str__(self): return "Lib" @@ -2048,7 +2157,7 @@ class Lib: py_ua_cfg.cb.on_typing = _cb_on_typing err = _pjsua.init(py_ua_cfg, log_cfg._cvt_to_pjsua(), - media_cfg._cvt_to_pjsua()) + media_cfg._cvt_to_pjsua()) self._err_check("init()", self, err) def destroy(self): @@ -2058,11 +2167,11 @@ class Lib: self._quit = 1 loop = 0 while self._quit != 2 and loop < 400: - _pjsua.handle_events(50) + self.handle_events(50) loop = loop + 1 _pjsua.destroy() _lib = None - + def start(self, with_thread=True): """Start the library. @@ -2087,6 +2196,7 @@ class Lib: timeout -- in milliseconds. """ + lck = self.auto_lock() return _pjsua.handle_events(timeout) def verify_sip_url(self, sip_url): @@ -2100,6 +2210,7 @@ class Lib: code is returned. """ + lck = self.auto_lock() return _pjsua.verify_sip_url(sip_url) def create_transport(self, type, cfg=None): @@ -2113,12 +2224,13 @@ class Lib: Transport object """ + lck = self.auto_lock() if not cfg: cfg=TransportConfig(type) err, tp_id = _pjsua.transport_create(type, cfg._cvt_to_pjsua()) self._err_check("create_transport()", self, err) return Transport(self, tp_id) - def create_account(self, acc_config, set_default=True): + def create_account(self, acc_config, set_default=True, cb=None): """ Create a new local pjsua account using the specified configuration. @@ -2126,35 +2238,41 @@ class Lib: acc_config -- AccountConfig set_default -- boolean to specify whether to use this as the default account. + cb -- AccountCallback instance. Return: Account instance """ + lck = self.auto_lock() err, acc_id = _pjsua.acc_add(acc_config._cvt_to_pjsua(), set_default) self._err_check("create_account()", self, err) - return Account(self, acc_id) + return Account(self, acc_id, cb) - def create_account_for_transport(self, transport, set_default=True): + def create_account_for_transport(self, transport, set_default=True, + cb=None): """Create a new local pjsua transport for the specified transport. Keyword arguments: transport -- the Transport instance. set_default -- boolean to specify whether to use this as the default account. + cb -- AccountCallback instance. Return: Account instance """ + lck = self.auto_lock() err, acc_id = _pjsua.acc_add_local(transport._id, set_default) self._err_check("create_account_for_transport()", self, err) - return Account(self, acc_id) + return Account(self, acc_id, cb) def hangup_all(self): """Hangup all calls. """ + lck = self.auto_lock() _pjsua.call_hangup_all() # Sound device API @@ -2166,6 +2284,7 @@ class Lib: list of SoundDeviceInfo. The index of the element specifies the device ID for the device. """ + lck = self.auto_lock() sdi_list = _pjsua.enum_snd_devs() info = [] for sdi in sdi_list: @@ -2178,6 +2297,7 @@ class Lib: Return: (capture_dev_id, playback_dev_id) tuple """ + lck = self.auto_lock() return _pjsua.get_snd_dev() def set_snd_dev(self, capture_dev, playback_dev): @@ -2188,6 +2308,7 @@ class Lib: playback_dev -- the device ID of playback device to be used. """ + lck = self.auto_lock() err = _pjsua.set_snd_dev(capture_dev, playback_dev) self._err_check("set_current_sound_devices()", self, err) @@ -2196,6 +2317,7 @@ class Lib: does not have sound device installed. """ + lck = self.auto_lock() err = _pjsua.set_null_snd_dev() self._err_check("set_null_snd_dev()", self, err) @@ -2209,6 +2331,7 @@ class Lib: conference bridge capacity. """ + lck = self.auto_lock() return _pjsua.conf_get_max_ports() def conf_connect(self, src_slot, dst_slot): @@ -2230,6 +2353,7 @@ class Lib: the destination/receiver. """ + lck = self.auto_lock() err = _pjsua.conf_connect(src_slot, dst_slot) self._err_check("conf_connect()", self, err) @@ -2243,6 +2367,7 @@ class Lib: the destination/receiver. """ + lck = self.auto_lock() err = _pjsua.conf_disconnect(src_slot, dst_slot) self._err_check("conf_disconnect()", self, err) @@ -2255,6 +2380,7 @@ class Lib: level -- Signal level adjustment. Value 1.0 means no level adjustment, while value 0 means to mute the port. """ + lck = self.auto_lock() err = _pjsua.conf_set_tx_level(slot, level) self._err_check("conf_set_tx_level()", self, err) @@ -2267,6 +2393,7 @@ class Lib: level -- Signal level adjustment. Value 1.0 means no level adjustment, while value 0 means to mute the port. """ + lck = self.auto_lock() err = _pjsua.conf_set_rx_level(slot, level) self._err_check("conf_set_rx_level()", self, err) @@ -2282,6 +2409,7 @@ class Lib: Return value: (tx_level, rx_level) tuple. """ + lck = self.auto_lock() err, tx_level, rx_level = _pjsua.conf_get_signal_level(slot) self._err_check("conf_get_signal_level()", self, err) return (tx_level, rx_level) @@ -2297,6 +2425,7 @@ class Lib: list of CodecInfo """ + lck = self.auto_lock() ci_list = _pjsua.enum_codecs() codec_info = [] for ci in ci_list: @@ -2313,6 +2442,7 @@ class Lib: priority -- Codec priority, which range is 0-255. """ + lck = self.auto_lock() err = _pjsua.codec_set_priority(name, priority) self._err_check("set_codec_priority()", self, err) @@ -2323,6 +2453,7 @@ class Lib: name -- codec name. """ + lck = self.auto_lock() cp = _pjsua.codec_get_param(name) if not cp: self._err_check("get_codec_parameter()", self, -1, @@ -2337,6 +2468,7 @@ class Lib: param -- codec parameter. """ + lck = self.auto_lock() err = _pjsua.codec_set_param(name, param._cvt_to_pjsua()) self._err_check("set_codec_parameter()", self, err) @@ -2353,6 +2485,7 @@ class Lib: WAV player ID """ + lck = self.auto_lock() opt = 0 if not loop: opt = opt + 1 @@ -2370,6 +2503,7 @@ class Lib: Conference slot number for the player """ + lck = self.auto_lock() slot = _pjsua.player_get_conf_port(player_id) if slot < 0: self._err_check("player_get_slot()", self, -1, @@ -2384,6 +2518,7 @@ class Lib: pos -- playback position, in samples """ + lck = self.auto_lock() err = _pjsua.player_set_pos(player_id, pos) self._err_check("player_set_pos()", self, err) @@ -2394,6 +2529,7 @@ class Lib: player_id -- the WAV player ID. """ + lck = self.auto_lock() err = _pjsua.player_destroy(player_id) self._err_check("player_destroy()", self, err) @@ -2410,6 +2546,7 @@ class Lib: Return: playlist_id """ + lck = self.auto_lock() opt = 0 if not loop: opt = opt + 1 @@ -2427,6 +2564,7 @@ class Lib: Conference slot number for the playlist """ + lck = self.auto_lock() slot = _pjsua.player_get_conf_port(playlist_id) if slot < 0: self._err_check("playlist_get_slot()", self, -1, @@ -2440,6 +2578,7 @@ class Lib: playlist_id -- the WAV playlist ID. """ + lck = self.auto_lock() err = _pjsua.player_destroy(playlist_id) self._err_check("playlist_destroy()", self, err) @@ -2453,6 +2592,7 @@ class Lib: WAV recorder ID """ + lck = self.auto_lock() err, rec_id = _pjsua.recorder_create(filename, 0, None, -1, 0) self._err_check("create_recorder()", self, err) return rec_id @@ -2467,6 +2607,7 @@ class Lib: Conference slot number for the recorder """ + lck = self.auto_lock() slot = _pjsua.recorder_get_conf_port(rec_id) if slot < 1: self._err_check("recorder_get_slot()", self, -1, @@ -2480,6 +2621,7 @@ class Lib: rec_id -- the WAV recorder ID. """ + lck = self.auto_lock() err = _pjsua.recorder_destroy(rec_id) self._err_check("recorder_destroy()", self, err) @@ -2502,48 +2644,31 @@ class Lib: msg_data.hdr_list = hdr_list return msg_data - # Internal dictionary manipulation for calls, accounts, and buddies + def auto_lock(self): + return _LibMutex(self._lock) - def _associate_call(self, call_id, call): - self.call[call_id] = call + # Internal dictionary manipulation for calls, accounts, and buddies def _lookup_call(self, call_id): - return self.call.has_key(call_id) and self.call[call_id] or None - - def _disassociate_call(self, call): - if self._lookup_call(call._id)==call: - del self.call[call._id] - - def _associate_account(self, acc_id, account): - self.account[acc_id] = account + return _pjsua.call_get_user_data(call_id) def _lookup_account(self, acc_id): - return self.account.has_key(acc_id) and self.account[acc_id] or None - - def _disassociate_account(self, account): - if self._lookup_account(account._id)==account: - del self.account[account._id] - - def _associate_buddy(self, buddy_id, buddy): - self.buddy[buddy_id] = buddy - uri = SIPUri(buddy.info().uri) - self.buddy_by_uri[(uri.user, uri.host)] = buddy + return _pjsua.acc_get_user_data(acc_id) def _lookup_buddy(self, buddy_id, uri=None): - buddy = self.buddy.has_key(buddy_id) and self.buddy[buddy_id] or None - if uri and not buddy: - sip_uri = SIPUri(uri) - buddy = self.buddy_by_uri.has_key( (sip_uri.user, sip_uri.host) ) \ - and self.buddy_by_uri[(sip_uri.user, sip_uri.host)] or \ - None + if buddy_id != -1: + buddy = _pjsua.buddy_get_user_data(buddy_id) + elif uri: + buddy_id = _pjsua.buddy_find(uri) + if buddy_id != -1: + buddy = _pjsua.buddy_get_user_data(buddy_id) + else: + buddy = None + else: + buddy = None + return buddy - def _disassociate_buddy(self, buddy): - if self._lookup_buddy(buddy._id)==buddy: - del self.buddy[buddy._id] - if self.buddy_by_uri.has_key(buddy.info().uri): - del self.buddy_by_uri[buddy.info().uri] - # Account allbacks def _cb_on_reg_state(self, acc_id): @@ -2551,11 +2676,13 @@ class Lib: if acc: acc._cb.on_reg_state() - def _cb_on_incoming_subscribe(self, acc_id, buddy_id, from_uri, pres_obj): + def _cb_on_incoming_subscribe(self, acc_id, buddy_id, from_uri, + contact_uri, pres_obj): acc = self._lookup_account(acc_id) if acc: buddy = self._lookup_buddy(buddy_id) - return acc._cb.on_incoming_subscribe(buddy, from_uri, pres_obj) + return acc._cb.on_incoming_subscribe(buddy, from_uri, contact_uri, + pres_obj) else: return (404, None) @@ -2571,7 +2698,14 @@ class Lib: def _cb_on_call_state(self, call_id): call = self._lookup_call(call_id) if call: + if call._id == -1: + call.attach_to_id(call_id) + done = (call.info().state == CallState.DISCONNECTED) call._cb.on_state() + if done: + _pjsua.call_set_user_data(call_id, 0) + else: + pass def _cb_on_call_media_state(self, call_id): call = self._lookup_call(call_id) @@ -2694,8 +2828,9 @@ def _cb_on_call_replaced(old_call_id, new_call_id): def _cb_on_reg_state(acc_id): _lib._cb_on_reg_state(acc_id) -def _cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, pres): - return _lib._cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, pres) +def _cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, contact_uri, pres): + return _lib._cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, + contact_uri, pres) def _cb_on_buddy_state(buddy_id): _lib._cb_on_buddy_state(buddy_id) @@ -2717,8 +2852,14 @@ def _worker_thread_main(arg): thread_desc = 0; err = _pjsua.thread_register("python worker", thread_desc) _lib._err_check("thread_register()", _lib, err) - while _lib._quit == 0: - _pjsua.handle_events(50) - _lib._quit = 2 - - + while _lib and _lib._quit == 0: + _lib.handle_events(50) + if _lib: + _lib._quit = 2 + +def _Trace(args): + if True: + print "** ", + for arg in args: + print arg, + print " **" |