Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjsip-apps / src / python / pjsua.py
1 # $Id$
2 #
3 # Object oriented PJSUA wrapper.
4 #
5 # Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
20 #
21
22 """Multimedia communication client library based on SIP protocol.
23
24 This implements a fully featured multimedia communication client 
25 library based on PJSIP stack (http://www.pjsip.org)
26
27
28 1. FEATURES
29
30   - Session Initiation Protocol (SIP) features:
31      - Basic registration and call
32      - Multiple accounts
33      - Call hold, attended and unattended call transfer
34      - Presence
35      - Instant messaging
36      - Multiple SIP accounts
37   - Media features:
38      - Audio
39      - Conferencing
40      - Narrowband and wideband
41      - Codecs: PCMA, PCMU, GSM, iLBC, Speex, G.722, L16
42      - RTP/RTCP
43      - Secure RTP (SRTP)
44      - WAV playback, recording, and playlist
45   - NAT traversal features
46      - Symmetric RTP
47      - STUN
48      - TURN
49      - ICE
50  
51
52 2. USING
53
54 See http://www.pjsip.org/trac/wiki/Python_SIP_Tutorial for a more thorough
55 tutorial. The paragraphs below explain basic tasks on using this module.
56
57
58 """
59 import _pjsua
60 import thread
61 import threading
62 import weakref
63 import time
64
65 class Error:
66     """Error exception class.
67     
68     Member documentation:
69
70     op_name  -- name of the operation that generated this error.
71     obj      -- the object that generated this error.
72     err_code -- the error code.
73
74     """
75     op_name = ""
76     obj = None
77     err_code = -1
78     _err_msg = ""
79
80     def __init__(self, op_name, obj, err_code, err_msg=""):
81         self.op_name = op_name
82         self.obj = obj
83         self.err_code = err_code
84         self._err_msg = err_msg
85
86     def err_msg(self):
87         "Retrieve the description of the error."
88         if self._err_msg != "":
89             return self._err_msg
90         self._err_msg = Lib.strerror(self.err_code)
91         return self._err_msg
92
93     def __str__(self):
94         return "Object: " + str(self.obj) + ", operation=" + self.op_name + \
95                ", error=" + self.err_msg()
96
97
98 # Constants
99 #
100
101 class TransportType:
102     """SIP transport type constants.
103     
104     Member documentation:
105     UNSPECIFIED -- transport type is unknown or unspecified
106     UDP         -- UDP transport
107     TCP         -- TCP transport
108     TLS         -- TLS transport
109     IPV6        -- this is not a transport type but rather a flag
110                    to select the IPv6 version of a transport
111     UDP_IPV6    -- IPv6 UDP transport
112     TCP_IPV6    -- IPv6 TCP transport
113     """
114     UNSPECIFIED = 0
115     UDP = 1
116     TCP = 2
117     TLS = 3
118     IPV6 = 128
119     UDP_IPV6 = UDP + IPV6
120     TCP_IPV6 = TCP + IPV6
121
122 class TransportFlag:
123     """Transport flags to indicate the characteristics of the transport.
124     
125     Member documentation:
126     
127     RELIABLE    -- transport is reliable.
128     SECURE      -- transport is secure.
129     DATAGRAM    -- transport is datagram based.
130     
131     """
132     RELIABLE = 1
133     SECURE = 2
134     DATAGRAM = 4
135
136 class CallRole:
137     """Call role constants.
138     
139     Member documentation:
140
141     CALLER  -- role is caller
142     CALLEE  -- role is callee
143
144     """
145     CALLER = 0
146     CALLEE = 1
147
148 class CallState:
149     """Call state constants.
150     
151     Member documentation:
152
153     NULL            -- call is not initialized.
154     CALLING         -- initial INVITE is sent.
155     INCOMING        -- initial INVITE is received.
156     EARLY           -- provisional response has been sent or received.
157     CONNECTING      -- 200/OK response has been sent or received.
158     CONFIRMED       -- ACK has been sent or received.
159     DISCONNECTED    -- call is disconnected.
160     """
161     NULL = 0
162     CALLING = 1
163     INCOMING = 2
164     EARLY = 3
165     CONNECTING = 4
166     CONFIRMED = 5
167     DISCONNECTED = 6
168
169
170 class MediaState:
171     """Call media state constants.
172     
173     Member documentation:
174
175     NULL        -- media is not available.
176     ACTIVE      -- media is active.
177     LOCAL_HOLD  -- media is put on-hold by local party.
178     REMOTE_HOLD -- media is put on-hold by remote party.
179     ERROR       -- media error (e.g. ICE negotiation failure).
180     """
181     NULL = 0
182     ACTIVE = 1
183     LOCAL_HOLD = 2
184     REMOTE_HOLD = 3
185     ERROR = 4
186
187
188 class MediaDir:
189     """Media direction constants.
190     
191     Member documentation:
192
193     NULL              -- media is not active
194     ENCODING          -- media is active in transmit/encoding direction only.
195     DECODING          -- media is active in receive/decoding direction only
196     ENCODING_DECODING -- media is active in both directions.
197     """
198     NULL = 0
199     ENCODING = 1
200     DECODING = 2
201     ENCODING_DECODING = 3
202
203
204 class PresenceActivity:
205     """Presence activities constants.
206     
207     Member documentation:
208
209     UNKNOWN -- the person activity is unknown
210     AWAY    -- the person is currently away
211     BUSY    -- the person is currently engaging in other activity
212     """
213     UNKNOWN = 0
214     AWAY = 1
215     BUSY = 2
216
217
218 class SubscriptionState:
219     """Presence subscription state constants.
220
221     """
222     NULL = 0
223     SENT = 1
224     ACCEPTED = 2
225     PENDING = 3
226     ACTIVE = 4
227     TERMINATED = 5
228     UNKNOWN = 6
229
230
231 class TURNConnType:
232     """These constants specifies the connection type to TURN server.
233     
234     Member documentation:
235     UDP     -- use UDP transport.
236     TCP     -- use TCP transport.
237     TLS     -- use TLS transport.
238     """
239     UDP = 17
240     TCP = 6
241     TLS = 255
242
243
244 class UAConfig:
245     """User agent configuration to be specified in Lib.init().
246     
247     Member documentation:
248
249     max_calls   -- maximum number of calls to be supported.
250     nameserver  -- list of nameserver hostnames or IP addresses. Nameserver
251                    must be configured if DNS SRV resolution is desired.
252     stun_domain -- if nameserver is configured, this can be used to query
253                    the STUN server with DNS SRV.
254     stun_host   -- the hostname or IP address of the STUN server. This will
255                    also be used if DNS SRV resolution for stun_domain fails.
256     user_agent  -- Optionally specify the user agent name.
257     """
258     max_calls = 4
259     nameserver = []
260     stun_domain = ""
261     stun_host = ""
262     user_agent = "pjsip python"
263     
264     def _cvt_from_pjsua(self, cfg):
265         self.max_calls = cfg.max_calls
266         self.thread_cnt = cfg.thread_cnt
267         self.nameserver = cfg.nameserver
268         self.stun_domain = cfg.stun_domain
269         self.stun_host = cfg.stun_host
270         self.user_agent = cfg.user_agent
271
272     def _cvt_to_pjsua(self):
273         cfg = _pjsua.config_default()
274         cfg.max_calls = self.max_calls
275         cfg.thread_cnt = 0
276         cfg.nameserver = self.nameserver
277         cfg.stun_domain = self.stun_domain
278         cfg.stun_host = self.stun_host
279         cfg.user_agent = self.user_agent
280         return cfg
281
282
283 class LogConfig:
284     """Logging configuration to be specified in Lib.init().
285     
286     Member documentation:
287
288     msg_logging   -- specify if SIP messages should be logged. Set to
289                      True.
290     level         -- specify the input verbosity level.
291     console_level -- specify the output verbosity level.
292     decor         -- specify log decoration.
293     filename      -- specify the log filename.
294     callback      -- specify callback to be called to write the logging
295                      messages. Sample function:
296
297                      def log_cb(level, str, len):
298                         print str,
299
300     """
301     msg_logging = True
302     level = 5
303     console_level = 5
304     decor = 0
305     filename = ""
306     callback = None
307     
308     def __init__(self, level=-1, filename="", callback=None,
309                  console_level=-1):
310         self._cvt_from_pjsua(_pjsua.logging_config_default())
311         if level != -1:
312             self.level = level
313         if filename != "":
314             self.filename = filename
315         if callback != None:
316             self.callback = callback
317         if console_level != -1:
318             self.console_level = console_level
319
320     def _cvt_from_pjsua(self, cfg):
321         self.msg_logging = cfg.msg_logging
322         self.level = cfg.level
323         self.console_level = cfg.console_level
324         self.decor = cfg.decor
325         self.filename = cfg.log_filename
326         self.callback = cfg.cb
327
328     def _cvt_to_pjsua(self):
329         cfg = _pjsua.logging_config_default()
330         cfg.msg_logging = self.msg_logging
331         cfg.level = self.level
332         cfg.console_level = self.console_level
333         cfg.decor = self.decor
334         cfg.log_filename = self.filename
335         cfg.cb = self.callback
336         return cfg
337
338
339 class MediaConfig:
340     """Media configuration to be specified in Lib.init().
341     
342     Member documentation:
343     
344     clock_rate          -- specify the core clock rate of the audio,
345                            most notably the conference bridge.
346     snd_clock_rate      -- optionally specify different clock rate for
347                            the sound device.
348     snd_auto_close_time -- specify the duration in seconds when the
349                            sound device should be closed after inactivity
350                            period.
351     channel_count       -- specify the number of channels to open the sound
352                            device and the conference bridge.
353     audio_frame_ptime   -- specify the length of audio frames in millisecond.
354     max_media_ports     -- specify maximum number of audio ports to be
355                            supported by the conference bridge.
356     quality             -- specify the audio quality setting (1-10)
357     ptime               -- specify the audio packet length of transmitted
358                            RTP packet.
359     no_vad              -- disable Voice Activity Detector (VAD) or Silence
360                            Detector (SD)
361     ilbc_mode           -- specify iLBC codec mode (must be 30 for now)
362     tx_drop_pct         -- randomly drop transmitted RTP packets (for
363                            simulation). Number is in percent.
364     rx_drop_pct         -- randomly drop received RTP packets (for
365                            simulation). Number is in percent.
366     ec_options          -- Echo Canceller option (specify zero).
367     ec_tail_len         -- specify Echo Canceller tail length in milliseconds.
368                            Value zero will disable the echo canceller.
369     jb_min              -- specify the minimum jitter buffer size in
370                            milliseconds. Put -1 for default.
371     jb_max              -- specify the maximum jitter buffer size in
372                            milliseconds. Put -1 for default.
373     enable_ice          -- enable Interactive Connectivity Establishment (ICE)
374     enable_turn         -- enable TURN relay. TURN server settings must also
375                            be configured.
376     turn_server         -- specify the domain or hostname or IP address of
377                            the TURN server, in "host[:port]" format.
378     turn_conn_type      -- specify connection type to the TURN server, from
379                            the TURNConnType constant.
380     turn_cred           -- specify AuthCred for the TURN credential.
381     """
382     clock_rate = 16000
383     snd_clock_rate = 0
384     snd_auto_close_time = 5
385     channel_count = 1
386     audio_frame_ptime = 20
387     max_media_ports = 32
388     quality = 6
389     ptime = 0
390     no_vad = False
391     ilbc_mode = 30
392     tx_drop_pct = 0
393     rx_drop_pct = 0
394     ec_options = 0
395     ec_tail_len = 256
396     jb_min = -1
397     jb_max = -1
398     enable_ice = True
399     enable_turn = False
400     turn_server = ""
401     turn_conn_type = TURNConnType.UDP
402     turn_cred = None
403      
404     def __init__(self):
405         default = _pjsua.media_config_default()
406         self._cvt_from_pjsua(default)
407
408     def _cvt_from_pjsua(self, cfg):
409         self.clock_rate = cfg.clock_rate
410         self.snd_clock_rate = cfg.snd_clock_rate
411         self.snd_auto_close_time = cfg.snd_auto_close_time
412         self.channel_count = cfg.channel_count
413         self.audio_frame_ptime = cfg.audio_frame_ptime
414         self.max_media_ports = cfg.max_media_ports
415         self.quality = cfg.quality
416         self.ptime = cfg.ptime
417         self.no_vad = cfg.no_vad
418         self.ilbc_mode = cfg.ilbc_mode
419         self.tx_drop_pct = cfg.tx_drop_pct
420         self.rx_drop_pct = cfg.rx_drop_pct
421         self.ec_options = cfg.ec_options
422         self.ec_tail_len = cfg.ec_tail_len
423         self.jb_min = cfg.jb_min
424         self.jb_max = cfg.jb_max
425         self.enable_ice = cfg.enable_ice
426         self.enable_turn = cfg.enable_turn
427         self.turn_server = cfg.turn_server
428         self.turn_conn_type = cfg.turn_conn_type
429         if cfg.turn_username:
430             self.turn_cred = AuthCred(cfg.turn_realm, cfg.turn_username,
431                                       cfg.turn_passwd, cfg.turn_passwd_type)
432         else:
433             self.turn_cred = None
434
435     def _cvt_to_pjsua(self):
436         cfg = _pjsua.media_config_default()
437         cfg.clock_rate = self.clock_rate
438         cfg.snd_clock_rate = self.snd_clock_rate
439         cfg.snd_auto_close_time = self.snd_auto_close_time
440         cfg.channel_count = self.channel_count
441         cfg.audio_frame_ptime = self.audio_frame_ptime
442         cfg.max_media_ports = self.max_media_ports
443         cfg.quality = self.quality
444         cfg.ptime = self.ptime
445         cfg.no_vad = self.no_vad
446         cfg.ilbc_mode = self.ilbc_mode
447         cfg.tx_drop_pct = self.tx_drop_pct
448         cfg.rx_drop_pct = self.rx_drop_pct
449         cfg.ec_options = self.ec_options
450         cfg.ec_tail_len = self.ec_tail_len
451         cfg.jb_min = self.jb_min
452         cfg.jb_max = self.jb_max
453         cfg.enable_ice = self.enable_ice
454         cfg.enable_turn = self.enable_turn
455         cfg.turn_server = self.turn_server
456         cfg.turn_conn_type = self.turn_conn_type
457         if self.turn_cred:
458             cfg.turn_realm = self.turn_cred.realm
459             cfg.turn_username = self.turn_cred.username
460             cfg.turn_passwd_type = self.turn_cred.passwd_type
461             cfg.turn_passwd = self.turn_cred.passwd
462         return cfg
463
464
465 class TransportConfig:
466     """SIP transport configuration class.
467     
468     Member configuration:
469
470     port        -- port number.
471     bound_addr  -- optionally specify the address to bind the socket to.
472                    Default is empty to bind to INADDR_ANY.
473     public_addr -- optionally override the published address for this
474                    transport. If empty, the default behavior is to get
475                    the public address from STUN or from the selected
476                    local interface. Format is "host:port".
477     """
478     port = 0
479     bound_addr = ""
480     public_addr = ""
481
482     def __init__(self, port=0, 
483                  bound_addr="", public_addr=""):
484         self.port = port
485         self.bound_addr = bound_addr
486         self.public_addr = public_addr
487
488     def _cvt_to_pjsua(self):
489         cfg = _pjsua.transport_config_default()
490         cfg.port = self.port
491         cfg.bound_addr = self.bound_addr
492         cfg.public_addr = self.public_addr
493         return cfg
494
495
496 class TransportInfo:
497     """SIP transport info.
498     
499     Member documentation:
500
501     type        -- transport type, from TransportType constants.
502     description -- longer description for this transport.
503     is_reliable -- True if transport is reliable.
504     is_secure   -- True if transport is secure.
505     is_datagram -- True if transport is datagram based.
506     host        -- the IP address of this transport.
507     port        -- the port number.
508     ref_cnt     -- number of objects referencing this transport.
509     """
510     type = ""
511     description = ""
512     is_reliable = False
513     is_secure = False
514     is_datagram = False
515     host = ""
516     port = 0
517     ref_cnt = 0
518     
519     def __init__(self, ti):
520         self.type = ti.type_name
521         self.description = ti.info
522         self.is_reliable = (ti.flag & TransportFlag.RELIABLE)
523         self.is_secure = (ti.flag & TransportFlag.SECURE)
524         self.is_datagram = (ti.flag & TransportFlag.DATAGRAM)
525         self.host = ti.addr
526         self.port = ti.port
527         self.ref_cnt = ti.usage_count
528     
529     
530 class Transport:
531     "SIP transport class."
532     _id = -1
533     _lib = None
534     _obj_name = ""
535
536     def __init__(self, lib, id):
537         self._lib = weakref.proxy(lib)
538         self._id = id
539         self._obj_name = "{Transport " + self.info().description + "}"
540         _Trace((self, 'created'))
541
542     def __del__(self):
543         _Trace((self, 'destroyed'))
544         
545     def __str__(self):
546         return self._obj_name
547
548     def info(self):
549         """Get TransportInfo.
550         """
551         lck = self._lib.auto_lock()
552         ti = _pjsua.transport_get_info(self._id)
553         if not ti:
554             self._lib._err_check("info()", self, -1, "Invalid transport")
555         return TransportInfo(ti)
556
557     def enable(self):
558         """Enable this transport."""
559         lck = self._lib.auto_lock()
560         err = _pjsua.transport_set_enable(self._id, True)
561         self._lib._err_check("enable()", self, err)
562
563     def disable(self):
564         """Disable this transport."""
565         lck = self._lib.auto_lock()
566         err = _pjsua.transport_set_enable(self._id, 0)
567         self._lib._err_check("disable()", self, err)
568
569     def close(self, force=False):
570         """Close and destroy this transport.
571
572         Keyword argument:
573         force   -- force deletion of this transport (not recommended).
574         """
575         lck = self._lib.auto_lock()
576         err = _pjsua.transport_close(self._id, force)
577         self._lib._err_check("close()", self, err)
578
579
580 class SIPUri:
581     """Helper class to parse the most important components of SIP URI.
582
583     Member documentation:
584
585     scheme    -- URI scheme ("sip" or "sips")
586     user      -- user part of the URI (may be empty)
587     host      -- host name part
588     port      -- optional port number (zero if port is not specified).
589     transport -- transport parameter, or empty if transport is not
590                  specified.
591
592     """
593     scheme = ""
594     user = ""
595     host = ""
596     port = 0
597     transport = ""
598
599     def __init__(self, uri=None):
600         if uri:
601             self.decode(uri)
602
603     def decode(self, uri):
604         """Parse SIP URL.
605
606         Keyword argument:
607         uri -- the URI string.
608
609         """
610         self.scheme, self.user, self.host, self.port, self.transport = \
611             _pjsua.parse_simple_uri(uri)
612
613     def encode(self):
614         """Encode this object into SIP URI string.
615
616         Return:
617             URI string.
618
619         """
620         output = self.scheme + ":"
621         if self.user and len(self.user):
622             output = output + self.user + "@"
623         output = output + self.host
624         if self.port:
625             output = output + ":" + output(self.port)
626         if self.transport:
627             output = output + ";transport=" + self.transport
628         return output
629
630
631 class AuthCred:
632     """Authentication credential for SIP or TURN account.
633     
634     Member documentation:
635
636     scheme      -- authentication scheme (default is "Digest")
637     realm       -- realm
638     username    -- username
639     passwd_type -- password encoding (zero for plain-text)
640     passwd      -- the password
641     """
642     scheme = "Digest"
643     realm = "*"
644     username = ""
645     passwd_type = 0
646     passwd = ""
647
648     def __init__(self, realm, username, passwd, scheme="Digest", passwd_type=0):
649         self.scheme = scheme
650         self.realm = realm
651         self.username = username
652         self.passwd_type = passwd_type
653         self.passwd = passwd
654
655
656 class AccountConfig:
657     """ This describes account configuration to create an account.
658
659     Member documentation:
660
661     priority                -- account priority for matching incoming
662                                messages.
663     id                      -- SIP URI of this account. This setting is
664                                mandatory.
665     force_contact           -- force to use this URI as Contact URI. Setting
666                                this value is generally not recommended.
667     reg_uri                 -- specify the registrar URI. Mandatory if
668                                registration is required.
669     reg_timeout             -- specify the SIP registration refresh interval
670                                in seconds.
671     require_100rel          -- specify if reliable provisional response is
672                                to be enforced (with Require header).
673     publish_enabled         -- specify if PUBLISH should be used. When
674                                enabled, the PUBLISH will be sent to the
675                                registrar.
676     pidf_tuple_id           -- optionally specify the tuple ID in outgoing
677                                PIDF document.
678     proxy                   -- list of proxy URI.
679     auth_cred               -- list of AuthCred containing credentials to
680                                authenticate against the registrars and
681                                the proxies.
682     auth_initial_send       -- specify if empty Authorization header should be
683                                sent. May be needed for IMS.
684     auth_initial_algorithm  -- when auth_initial_send is enabled, optionally
685                                specify the authentication algorithm to use.
686                                Valid values are "md5", "akav1-md5", or
687                                "akav2-md5". 
688     transport_id            -- optionally specify the transport ID to be used
689                                by this account. Shouldn't be needed unless
690                                for specific requirements (e.g. in multi-homed
691                                scenario).
692     allow_contact_rewrite   -- specify whether the account should learn its
693                                Contact address from REGISTER response and 
694                                update the registration accordingly. Default is
695                                True.
696     ka_interval             -- specify the interval to send NAT keep-alive 
697                                packet.
698     ka_data                 -- specify the NAT keep-alive packet contents.
699     use_srtp                -- specify the SRTP usage policy. Valid values
700                                are: 0=disable, 1=optional, 2=mandatory.
701                                Default is 0.
702     srtp_secure_signaling   -- specify the signaling security level required
703                                by SRTP. Valid values are: 0=no secure 
704                                transport is required, 1=hop-by-hop secure
705                                transport such as TLS is required, 2=end-to-
706                                end secure transport is required (i.e. "sips").
707     """
708     priority = 0
709     id = ""
710     force_contact = ""
711     reg_uri = ""
712     reg_timeout = 0
713     require_100rel = False
714     publish_enabled = False
715     pidf_tuple_id = ""
716     proxy = []
717     auth_cred = []
718     auth_initial_send = False
719     auth_initial_algorithm = ""
720     transport_id = -1
721     allow_contact_rewrite = True
722     ka_interval = 15
723     ka_data = "\r\n"
724     use_srtp = 0
725     srtp_secure_signaling = 1
726
727     def __init__(self, domain="", username="", password="", 
728                  display="", registrar="", proxy=""):
729         """
730         Construct account config. If domain argument is specified, 
731         a typical configuration will be built.
732
733         Keyword arguments:
734         domain    -- domain name of the server.
735         username  -- user name.
736         password  -- plain-text password.
737         display   -- optional display name for the user name.
738         registrar -- the registrar URI. If domain name is specified
739                      and this argument is empty, the registrar URI
740                      will be constructed from the domain name.
741         proxy     -- the proxy URI. If domain name is specified
742                      and this argument is empty, the proxy URI
743                      will be constructed from the domain name.
744
745         """
746         default = _pjsua.acc_config_default()
747         self._cvt_from_pjsua(default)
748         if domain!="":
749             self.build_config(domain, username, password,
750                               display, registrar, proxy)
751
752     def build_config(self, domain, username, password, display="",
753                      registrar="", proxy=""):
754         """
755         Construct account config. If domain argument is specified, 
756         a typical configuration will be built.
757
758         Keyword arguments:
759         domain    -- domain name of the server.
760         username  -- user name.
761         password  -- plain-text password.
762         display   -- optional display name for the user name.
763         registrar -- the registrar URI. If domain name is specified
764                      and this argument is empty, the registrar URI
765                      will be constructed from the domain name.
766         proxy     -- the proxy URI. If domain name is specified
767                      and this argument is empty, the proxy URI
768                      will be constructed from the domain name.
769
770         """
771         if display != "":
772             display = display + " "
773         userpart = username
774         if userpart != "":
775             userpart = userpart + "@"
776         self.id = display + "<sip:" + userpart + domain + ">"
777         self.reg_uri = registrar
778         if self.reg_uri == "":
779             self.reg_uri = "sip:" + domain
780         if proxy == "":
781             proxy = "sip:" + domain + ";lr"
782         if proxy.find(";lr") == -1:
783             proxy = proxy + ";lr"
784         self.proxy.append(proxy)
785         if username != "":
786             self.auth_cred.append(AuthCred("*", username, password))
787     
788     def _cvt_from_pjsua(self, cfg):
789         self.priority = cfg.priority
790         self.id = cfg.id
791         self.force_contact = cfg.force_contact
792         self.reg_uri = cfg.reg_uri
793         self.reg_timeout = cfg.reg_timeout
794         self.require_100rel = cfg.require_100rel
795         self.publish_enabled = cfg.publish_enabled
796         self.pidf_tuple_id = cfg.pidf_tuple_id
797         self.proxy = cfg.proxy
798         for cred in cfg.cred_info:
799             self.auth_cred.append(AuthCred(cred.realm, cred.username, 
800                                            cred.data, cred.scheme,
801                                            cred.data_type))
802         self.auth_initial_send = cfg.auth_initial_send
803         self.auth_initial_algorithm = cfg.auth_initial_algorithm
804         self.transport_id = cfg.transport_id
805         self.allow_contact_rewrite = cfg.allow_contact_rewrite
806         self.ka_interval = cfg.ka_interval
807         self.ka_data = cfg.ka_data
808         self.use_srtp = cfg.use_srtp
809         self.srtp_secure_signaling = cfg.srtp_secure_signaling
810
811     def _cvt_to_pjsua(self):
812         cfg = _pjsua.acc_config_default()
813         cfg.priority = self.priority
814         cfg.id = self.id
815         cfg.force_contact = self.force_contact
816         cfg.reg_uri = self.reg_uri
817         cfg.reg_timeout = self.reg_timeout
818         cfg.require_100rel = self.require_100rel
819         cfg.publish_enabled = self.publish_enabled
820         cfg.pidf_tuple_id = self.pidf_tuple_id
821         cfg.proxy = self.proxy
822         for cred in self.auth_cred:
823             c = _pjsua.Pjsip_Cred_Info()
824             c.realm = cred.realm
825             c.scheme = cred.scheme
826             c.username = cred.username
827             c.data_type = cred.passwd_type
828             c.data = cred.passwd
829             cfg.cred_info.append(c)
830         cfg.auth_initial_send = self.auth_initial_send
831         cfg.auth_initial_algorithm = self.auth_initial_algorithm
832         cfg.transport_id = self.transport_id
833         cfg.allow_contact_rewrite = self.allow_contact_rewrite
834         cfg.ka_interval = self.ka_interval
835         cfg.ka_data = self.ka_data
836         cfg.use_srtp = self.use_srtp
837         cfg.srtp_secure_signaling = self.srtp_secure_signaling
838         return cfg
839  
840  
841 # Account information
842 class AccountInfo:
843     """This describes Account info. Application retrives account info
844     with Account.info().
845
846     Member documentation:
847
848     is_default      -- True if this is the default account.
849     uri             -- the account URI.
850     reg_active      -- True if registration is active for this account.
851     reg_expires     -- contains the current registration expiration value,
852                        in seconds.
853     reg_status      -- the registration status. If the value is less than
854                        700, it specifies SIP status code. Value greater than
855                        this specifies the error code.
856     reg_reason      -- contains the registration status text (e.g. the
857                        error message).
858     online_status   -- the account's presence online status, True if it's 
859                        publishing itself as online.
860     online_text     -- the account's presence status text.
861
862     """
863     is_default = False
864     uri = ""
865     reg_active = False
866     reg_expires = -1
867     reg_status = 0
868     reg_reason = ""
869     online_status = False
870     online_text = ""
871
872     def __init__(self, ai):
873         self.is_default = ai.is_default
874         self.uri = ai.acc_uri
875         self.reg_active = ai.has_registration
876         self.reg_expires = ai.expires
877         self.reg_status = ai.status
878         self.reg_reason = ai.status_text
879         self.online_status = ai.online_status
880         self.online_text = ai.online_status_text
881
882 # Account callback
883 class AccountCallback:
884     """Class to receive notifications on account's events.
885
886     Derive a class from this class and register it to the Account object
887     using Account.set_callback() to start receiving events from the Account
888     object.
889
890     Member documentation:
891
892     account     -- the Account object.
893
894     """
895     account = None
896
897     def __init__(self, account=None):
898         self._set_account(account)
899
900     def __del__(self):
901         pass
902
903     def _set_account(self, account):
904         if account:
905             self.account = weakref.proxy(account)
906         else:
907             self.account = None
908
909     def on_reg_state(self):
910         """Notification that the registration status has changed.
911         """
912         pass
913
914     def on_incoming_call(self, call):
915         """Notification about incoming call.
916
917         Unless this callback is implemented, the default behavior is to
918         reject the call with default status code.
919
920         Keyword arguments:
921         call    -- the new incoming call
922         """
923         call.hangup()
924
925     def on_incoming_subscribe(self, buddy, from_uri, contact_uri, pres_obj):
926         """Notification when incoming SUBSCRIBE request is received. 
927         
928         Application may use this callback to authorize the incoming 
929         subscribe request (e.g. ask user permission if the request 
930         should be granted)
931
932         Keyword arguments:
933         buddy       -- The buddy object, if buddy is found. Otherwise
934                        the value is None.
935         from_uri    -- The URI string of the sender.
936         pres_obj    -- Opaque presence subscription object, which is
937                        needed by Account.pres_notify()
938
939         Return:
940             Tuple (code, reason), where:
941              code:      The status code. If code is >= 300, the
942                         request is rejected. If code is 200, the
943                         request is accepted and NOTIFY will be sent
944                         automatically. If code is 202, application
945                         must accept or reject the request later with
946                         Account.press_notify().
947              reason:    Optional reason phrase, or None to use the
948                         default reasoh phrase for the status code.
949         """
950         return (200, None)
951
952     def on_pager(self, from_uri, contact, mime_type, body):
953         """
954         Notification that incoming instant message is received on
955         this account.
956
957         Keyword arguments:
958         from_uri   -- sender's URI
959         contact    -- sender's Contact URI
960         mime_type  -- MIME type of the instant message body
961         body       -- the instant message body
962
963         """
964         pass
965
966     def on_pager_status(self, to_uri, body, im_id, code, reason):
967         """
968         Notification about the delivery status of previously sent
969         instant message.
970
971         Keyword arguments:
972         to_uri  -- the destination URI of the message
973         body    -- the message body
974         im_id   -- message ID
975         code    -- SIP status code
976         reason  -- SIP reason phrase
977
978         """
979         pass
980
981     def on_typing(self, from_uri, contact, is_typing):
982         """
983         Notification that remote is typing or stop typing.
984
985         Keyword arguments:
986         buddy     -- Buddy object for the sender, if found. Otherwise
987                      this will be None
988         from_uri  -- sender's URI of the indication
989         contact   -- sender's contact URI
990         is_typing -- boolean to indicate whether remote is currently
991                      typing an instant message.
992
993         """
994         pass
995
996     def on_mwi_info(self, body):
997         """
998         Notification about change in Message Summary / Message Waiting
999         Indication (RFC 3842) status. MWI subscription must be enabled
1000         in the account config to receive this notification.
1001
1002         Keyword arguments:
1003         body      -- String containing message body as received in the
1004                      NOTIFY request.
1005
1006         """
1007         pass
1008
1009
1010
1011 class Account:
1012     """This describes SIP account class.
1013
1014     PJSUA accounts provide identity (or identities) of the user who is 
1015     currently using the application. In SIP terms, the identity is used 
1016     as the From header in outgoing requests.
1017
1018     Account may or may not have client registration associated with it. 
1019     An account is also associated with route set and some authentication 
1020     credentials, which are used when sending SIP request messages using 
1021     the account. An account also has presence's online status, which 
1022     will be reported to remote peer when they subscribe to the account's 
1023     presence, or which is published to a presence server if presence 
1024     publication is enabled for the account.
1025
1026     Account is created with Lib.create_account(). At least one account 
1027     MUST be created. If no user association is required, application can 
1028     create a userless account by calling Lib.create_account_for_transport().
1029     A userless account identifies local endpoint instead of a particular 
1030     user, and it correspond with a particular transport instance.
1031
1032     Also one account must be set as the default account, which is used as 
1033     the account to use when PJSUA fails to match a request with any other
1034     accounts.
1035
1036     """
1037     _id = -1        
1038     _lib = None
1039     _cb = AccountCallback(None)
1040     _obj_name = ""
1041
1042     def __init__(self, lib, id, cb=None):
1043         """Construct this class. This is normally called by Lib class and
1044         not by application.
1045
1046         Keyword arguments:
1047         lib -- the Lib instance.
1048         id  -- the pjsua account ID.
1049         cb  -- AccountCallback instance to receive events from this Account.
1050                If callback is not specified here, it must be set later
1051                using set_callback().
1052         """
1053         self._id = id
1054         self._lib = weakref.ref(lib)
1055         self._obj_name = "{Account " + self.info().uri + "}"
1056         self.set_callback(cb)
1057         _pjsua.acc_set_user_data(self._id, self)
1058         _Trace((self, 'created'))
1059
1060     def __del__(self):
1061         if self._id != -1:
1062             _pjsua.acc_set_user_data(self._id, 0)
1063         _Trace((self, 'destroyed'))
1064
1065     def __str__(self):
1066         return self._obj_name
1067
1068     def info(self):
1069         """Retrieve AccountInfo for this account.
1070         """
1071         lck = self._lib().auto_lock()
1072         ai = _pjsua.acc_get_info(self._id)
1073         if ai==None:
1074             self._lib()._err_check("info()", self, -1, "Invalid account")
1075         return AccountInfo(ai)
1076
1077     def is_valid(self):
1078         """
1079         Check if this account is still valid.
1080
1081         """
1082         lck = self._lib().auto_lock()
1083         return _pjsua.acc_is_valid(self._id)
1084
1085     def set_callback(self, cb):
1086         """Register callback to receive notifications from this object.
1087
1088         Keyword argument:
1089         cb  -- AccountCallback instance.
1090
1091         """
1092         if cb:
1093             self._cb = cb
1094         else:
1095             self._cb = AccountCallback(self)
1096         self._cb._set_account(self)
1097
1098     def set_default(self):
1099         """ Set this account as default account to send outgoing requests
1100         and as the account to receive incoming requests when more exact
1101         matching criteria fails.
1102         """
1103         lck = self._lib().auto_lock()
1104         err = _pjsua.acc_set_default(self._id)
1105         self._lib()._err_check("set_default()", self, err)
1106
1107     def is_default(self):
1108         """ Check if this account is the default account.
1109
1110         """
1111         lck = self._lib().auto_lock()
1112         def_id = _pjsua.acc_get_default()
1113         return self.is_valid() and def_id==self._id
1114
1115     def delete(self):
1116         """ Delete this account.
1117         
1118         """
1119         lck = self._lib().auto_lock()
1120         err = _pjsua.acc_set_user_data(self._id, 0)
1121         self._lib()._err_check("delete()", self, err)
1122         err = _pjsua.acc_del(self._id)
1123         self._lib()._err_check("delete()", self, err)
1124         self._id = -1
1125
1126     def set_basic_status(self, is_online):
1127         """ Set basic presence status of this account.
1128
1129         Keyword argument:
1130         is_online   -- boolean to indicate basic presence availability.
1131
1132         """
1133         lck = self._lib().auto_lock()
1134         err = _pjsua.acc_set_online_status(self._id, is_online)
1135         self._lib()._err_check("set_basic_status()", self, err)
1136
1137     def set_presence_status(self, is_online, 
1138                             activity=PresenceActivity.UNKNOWN, 
1139                             pres_text="", rpid_id=""):
1140         """ Set presence status of this account. 
1141         
1142         Keyword arguments:
1143         is_online   -- boolean to indicate basic presence availability
1144         activity    -- value from PresenceActivity
1145         pres_text   -- optional string to convey additional information about
1146                        the activity (such as "On the phone")
1147         rpid_id     -- optional string to be placed as RPID ID. 
1148
1149         """
1150         lck = self._lib().auto_lock()
1151         err = _pjsua.acc_set_online_status2(self._id, is_online, activity,
1152                                             pres_text, rpid_id)
1153         self._lib()._err_check("set_presence_status()", self, err)
1154
1155     def set_registration(self, renew):
1156         """Manually renew registration or unregister from the server.
1157
1158         Keyword argument:
1159         renew   -- boolean to indicate whether registration is renewed.
1160                    Setting this value for False will trigger unregistration.
1161
1162         """
1163         lck = self._lib().auto_lock()
1164         err = _pjsua.acc_set_registration(self._id, renew)
1165         self._lib()._err_check("set_registration()", self, err)
1166
1167     def set_transport(self, transport):
1168         """Set this account to only use the specified transport to send
1169         outgoing requests.
1170
1171         Keyword argument:
1172         transport   -- Transport object.
1173
1174         """
1175         lck = self._lib().auto_lock()
1176         err = _pjsua.acc_set_transport(self._id, transport._id)
1177         self._lib()._err_check("set_transport()", self, err)
1178
1179     def make_call(self, dst_uri, cb=None, hdr_list=None):
1180         """Make outgoing call to the specified URI.
1181
1182         Keyword arguments:
1183         dst_uri  -- Destination SIP URI.
1184         cb       -- CallCallback instance to be installed to the newly
1185                     created Call object. If this CallCallback is not
1186                     specified (i.e. None is given), it must be installed
1187                     later using call.set_callback().
1188         hdr_list -- Optional list of headers to be sent with outgoing
1189                     INVITE
1190
1191         Return:
1192             Call instance.
1193         """
1194         lck = self._lib().auto_lock()
1195         call = Call(self._lib(), -1, cb)
1196         err, cid = _pjsua.call_make_call(self._id, dst_uri, 0, 
1197                                          call, Lib._create_msg_data(hdr_list))
1198         self._lib()._err_check("make_call()", self, err)
1199         call.attach_to_id(cid)
1200         return call
1201
1202     def add_buddy(self, uri, cb=None):
1203         """Add new buddy.
1204
1205         Keyword argument:
1206         uri     -- SIP URI of the buddy
1207         cb      -- BuddyCallback instance to be installed to the newly
1208                    created Buddy object. If this callback is not specified
1209                    (i.e. None is given), it must be installed later using
1210                    buddy.set_callback().
1211
1212         Return:
1213             Buddy object
1214         """
1215         lck = self._lib().auto_lock()
1216         buddy_cfg = _pjsua.buddy_config_default()
1217         buddy_cfg.uri = uri
1218         buddy_cfg.subscribe = False
1219         err, buddy_id = _pjsua.buddy_add(buddy_cfg)
1220         self._lib()._err_check("add_buddy()", self, err)
1221         buddy = Buddy(self._lib(), buddy_id, self, cb)
1222         return buddy
1223
1224     def pres_notify(self, pres_obj, state, reason="", hdr_list=None):
1225         """Send NOTIFY to inform account presence status or to terminate
1226         server side presence subscription.
1227         
1228         Keyword arguments:
1229         pres_obj    -- The subscription object from on_incoming_subscribe()
1230                        callback
1231         state       -- Subscription state, from SubscriptionState
1232         reason      -- Optional reason phrase.
1233         hdr_list    -- Optional header list.
1234         """
1235         lck = self._lib().auto_lock()
1236         _pjsua.acc_pres_notify(self._id, pres_obj, state, reason, 
1237                                Lib._create_msg_data(hdr_list))
1238     
1239     def send_pager(self, uri, text, im_id=0, content_type="text/plain", \
1240                    hdr_list=None):
1241         """Send instant message to arbitrary URI.
1242
1243         Keyword arguments:
1244         text         -- Instant message to be sent
1245         uri          -- URI to send the Instant Message to.
1246         im_id        -- Optional instant message ID to identify this
1247                         instant message when delivery status callback
1248                         is called.
1249         content_type -- MIME type identifying the instant message
1250         hdr_list     -- Optional list of headers to be sent with the
1251                         request.
1252
1253         """
1254         lck = self._lib().auto_lock()
1255         err = _pjsua.im_send(self._id, uri, \
1256                              content_type, text, \
1257                              Lib._create_msg_data(hdr_list), \
1258                              im_id)
1259         self._lib()._err_check("send_pager()", self, err)
1260
1261 class CallCallback:
1262     """Class to receive event notification from Call objects. 
1263
1264     Use Call.set_callback() method to install instance of this callback 
1265     class to receive event notifications from the call object.
1266
1267     Member documentation:
1268
1269     call    -- the Call object.
1270
1271     """
1272     call = None
1273
1274     def __init__(self, call=None):
1275         self._set_call(call)
1276
1277     def __del__(self):
1278         pass
1279
1280     def _set_call(self, call):
1281         if call:
1282             self.call = weakref.proxy(call)
1283         else:
1284             self.call = None
1285
1286     def on_state(self):
1287         """Notification that the call's state has changed.
1288
1289         """
1290         pass
1291
1292     def on_media_state(self):
1293         """Notification that the call's media state has changed.
1294
1295         """
1296         pass
1297
1298     def on_dtmf_digit(self, digits):
1299         """Notification on incoming DTMF digits.
1300
1301         Keyword argument:
1302         digits  -- string containing the received digits.
1303
1304         """
1305         pass
1306
1307     def on_transfer_request(self, dst, code):
1308         """Notification that call is being transfered by remote party. 
1309
1310         Application can decide to accept/reject transfer request by returning
1311         code greater than or equal to 500. The default behavior is to accept 
1312         the transfer by returning 202.
1313
1314         Keyword arguments:
1315         dst     -- string containing the destination URI
1316         code    -- the suggested status code to return to accept the request.
1317
1318         Return:
1319         the callback should return 202 to accept the request, or 300-699 to
1320         reject the request.
1321
1322         """
1323         return code
1324
1325     def on_transfer_status(self, code, reason, final, cont):
1326         """
1327         Notification about the status of previous call transfer request. 
1328
1329         Keyword arguments:
1330         code    -- SIP status code to indicate completion status.
1331         text    -- SIP status reason phrase.
1332         final   -- if True then this is a final status and no further
1333                    notifications will be sent for this call transfer
1334                    status.
1335         cont    -- suggested return value.
1336
1337         Return:
1338         If the callback returns false then no further notification will
1339         be sent for the transfer request for this call.
1340
1341         """
1342         return cont
1343
1344     def on_replace_request(self, code, reason):
1345         """Notification when incoming INVITE with Replaces header is received. 
1346
1347         Application may reject the request by returning value greather than
1348         or equal to 500. The default behavior is to accept the request.
1349
1350         Keyword arguments:
1351         code    -- default status code to return
1352         reason  -- default reason phrase to return
1353
1354         Return:
1355         The callback should return (code, reason) tuple.
1356
1357         """
1358         return code, reason
1359
1360     def on_replaced(self, new_call):
1361         """
1362         Notification that this call will be replaced with new_call. 
1363         After this callback is called, this call will be disconnected.
1364
1365         Keyword arguments:
1366         new_call    -- the new call that will replace this call.
1367         """
1368         pass
1369
1370     def on_pager(self, mime_type, body):
1371         """
1372         Notification that incoming instant message is received on
1373         this call.
1374
1375         Keyword arguments:
1376         mime_type  -- MIME type of the instant message body.
1377         body       -- the instant message body.
1378
1379         """
1380         pass
1381
1382     def on_pager_status(self, body, im_id, code, reason):
1383         """
1384         Notification about the delivery status of previously sent
1385         instant message.
1386
1387         Keyword arguments:
1388         body    -- message body
1389         im_id   -- message ID
1390         code    -- SIP status code
1391         reason  -- SIP reason phrase
1392
1393         """
1394         pass
1395
1396     def on_typing(self, is_typing):
1397         """
1398         Notification that remote is typing or stop typing.
1399
1400         Keyword arguments:
1401         is_typing -- boolean to indicate whether remote is currently
1402                      typing an instant message.
1403
1404         """
1405         pass
1406
1407
1408 class CallInfo:
1409     """This structure contains various information about Call.
1410
1411     Application may retrieve this information with Call.info().
1412
1413     Member documentation:
1414
1415     role            -- CallRole
1416     account         -- Account object.
1417     uri             -- SIP URI of local account.
1418     contact         -- local Contact URI.
1419     remote_uri      -- remote SIP URI.
1420     remote_contact  -- remote Contact URI
1421     sip_call_id     -- call's Call-ID identification
1422     state           -- CallState
1423     state_text      -- state text.
1424     last_code       -- last SIP status code
1425     last_reason     -- text phrase for last_code
1426     media_state     -- MediaState
1427     media_dir       -- MediaDir
1428     conf_slot       -- conference slot number for this call.
1429     call_time       -- call's connected duration in seconds.
1430     total_time      -- total call duration in seconds.
1431     """
1432     role = CallRole.CALLER
1433     account = None
1434     uri = ""
1435     contact = ""
1436     remote_uri = ""
1437     remote_contact = ""
1438     sip_call_id = ""
1439     state = CallState.NULL
1440     state_text = ""
1441     last_code = 0
1442     last_reason = ""
1443     media_state = MediaState.NULL
1444     media_dir = MediaDir.NULL
1445     conf_slot = -1
1446     call_time = 0
1447     total_time = 0
1448
1449     def __init__(self, lib=None, ci=None):
1450         if lib and ci:
1451             self._cvt_from_pjsua(lib, ci)
1452
1453     def _cvt_from_pjsua(self, lib, ci):
1454         self.role = ci.role
1455         self.account = lib._lookup_account(ci.acc_id)
1456         self.uri = ci.local_info
1457         self.contact = ci.local_contact
1458         self.remote_uri = ci.remote_info
1459         self.remote_contact = ci.remote_contact
1460         self.sip_call_id = ci.call_id
1461         self.state = ci.state
1462         self.state_text = ci.state_text
1463         self.last_code = ci.last_status
1464         self.last_reason = ci.last_status_text
1465         self.media_state = ci.media_status
1466         self.media_dir = ci.media_dir
1467         self.conf_slot = ci.conf_slot
1468         self.call_time = ci.connect_duration / 1000
1469         self.total_time = ci.total_duration / 1000
1470
1471
1472 class Call:
1473     """This class represents SIP call.
1474
1475     Application initiates outgoing call with Account.make_call(), and
1476     incoming calls are reported in AccountCallback.on_incoming_call().
1477     """
1478     _id = -1
1479     _cb = None
1480     _lib = None
1481     _obj_name = ""
1482
1483     def __init__(self, lib, call_id, cb=None):
1484         self._lib = weakref.ref(lib)
1485         self.set_callback(cb)
1486         self.attach_to_id(call_id)
1487         _Trace((self, 'created'))
1488
1489     def __del__(self):
1490         if self._id != -1:
1491             _pjsua.call_set_user_data(self._id, 0)
1492         _Trace((self, 'destroyed'))
1493
1494     def __str__(self):
1495         return self._obj_name
1496
1497     def attach_to_id(self, call_id):
1498         lck = self._lib().auto_lock()
1499         if self._id != -1:
1500             _pjsua.call_set_user_data(self._id, 0)
1501         self._id = call_id
1502         if self._id != -1:
1503             _pjsua.call_set_user_data(self._id, self)
1504             self._obj_name = "{Call " + self.info().remote_uri + "}"
1505         else:
1506             self._obj_name = "{Call object}"
1507
1508     def set_callback(self, cb):
1509         """
1510         Set callback object to retrieve event notifications from this call.
1511
1512         Keyword arguments:
1513         cb  -- CallCallback instance.
1514         """
1515         if cb:
1516             self._cb = cb
1517         else:
1518             self._cb = CallCallback(self)
1519         self._cb._set_call(self)
1520
1521     def info(self):
1522         """
1523         Get the CallInfo.
1524         """
1525         lck = self._lib().auto_lock()
1526         ci = _pjsua.call_get_info(self._id)
1527         if not ci:
1528             self._lib()._err_check("info", self, -1, "Invalid call")
1529         call_info = CallInfo(self._lib(), ci)
1530         return call_info
1531
1532     def is_valid(self):
1533         """
1534         Check if this call is still valid.
1535         """
1536         lck = self._lib().auto_lock()
1537         return _pjsua.call_is_active(self._id)
1538
1539     def dump_status(self, with_media=True, indent="", max_len=1024):
1540         """
1541         Dump the call status.
1542         """
1543         lck = self._lib().auto_lock()
1544         return _pjsua.call_dump(self._id, with_media, max_len, indent)
1545
1546     def answer(self, code=200, reason="", hdr_list=None):
1547         """
1548         Send provisional or final response to incoming call.
1549
1550         Keyword arguments:
1551         code     -- SIP status code.
1552         reason   -- Reason phrase. Put empty to send default reason
1553                     phrase for the status code.
1554         hdr_list -- Optional list of headers to be sent with the
1555                     INVITE response.
1556
1557         """
1558         lck = self._lib().auto_lock()
1559         err = _pjsua.call_answer(self._id, code, reason, 
1560                                    Lib._create_msg_data(hdr_list))
1561         self._lib()._err_check("answer()", self, err)
1562
1563     def hangup(self, code=603, reason="", hdr_list=None):
1564         """
1565         Terminate the call.
1566
1567         Keyword arguments:
1568         code     -- SIP status code.
1569         reason   -- Reason phrase. Put empty to send default reason
1570                     phrase for the status code.
1571         hdr_list -- Optional list of headers to be sent with the
1572                     message.
1573
1574         """
1575         lck = self._lib().auto_lock()
1576         err = _pjsua.call_hangup(self._id, code, reason, 
1577                                    Lib._create_msg_data(hdr_list))
1578         self._lib()._err_check("hangup()", self, err)
1579
1580     def hold(self, hdr_list=None):
1581         """
1582         Put the call on hold.
1583
1584         Keyword arguments:
1585         hdr_list -- Optional list of headers to be sent with the
1586                     message.
1587         """
1588         lck = self._lib().auto_lock()
1589         err = _pjsua.call_set_hold(self._id, Lib._create_msg_data(hdr_list))
1590         self._lib()._err_check("hold()", self, err)
1591
1592     def unhold(self, hdr_list=None):
1593         """
1594         Release the call from hold.
1595
1596         Keyword arguments:
1597         hdr_list -- Optional list of headers to be sent with the
1598                     message.
1599
1600         """
1601         lck = self._lib().auto_lock()
1602         err = _pjsua.call_reinvite(self._id, True, 
1603                                      Lib._create_msg_data(hdr_list))
1604         self._lib()._err_check("unhold()", self, err)
1605
1606     def reinvite(self, hdr_list=None):
1607         """
1608         Send re-INVITE and optionally offer new codecs to use.
1609
1610         Keyword arguments:
1611         hdr_list   -- Optional list of headers to be sent with the
1612                       message.
1613
1614         """
1615         lck = self._lib().auto_lock()
1616         err = _pjsua.call_reinvite(self._id, True, 
1617                                      Lib._create_msg_data(hdr_list))
1618         self._lib()._err_check("reinvite()", self, err)
1619
1620     def update(self, hdr_list=None, options=0):
1621         """
1622         Send UPDATE and optionally offer new codecs to use.
1623
1624         Keyword arguments:
1625         hdr_list   -- Optional list of headers to be sent with the
1626                       message.
1627         options    -- Must be zero for now.
1628
1629         """
1630         lck = self._lib().auto_lock()
1631         err = _pjsua.call_update(self._id, options, 
1632                                    Lib._create_msg_data(hdr_list))
1633         self._lib()._err_check("update()", self, err)
1634
1635     def transfer(self, dest_uri, hdr_list=None):
1636         """
1637         Transfer the call to new destination.
1638
1639         Keyword arguments:
1640         dest_uri -- Specify the SIP URI to transfer the call to.
1641         hdr_list -- Optional list of headers to be sent with the
1642                     message.
1643
1644         """
1645         lck = self._lib().auto_lock()
1646         err = _pjsua.call_xfer(self._id, dest_uri, 
1647                                  Lib._create_msg_data(hdr_list))
1648         self._lib()._err_check("transfer()", self, err)
1649
1650     def transfer_to_call(self, call, hdr_list=None, options=0):
1651         """
1652         Attended call transfer.
1653
1654         Keyword arguments:
1655         call     -- The Call object to transfer call to.
1656         hdr_list -- Optional list of headers to be sent with the
1657                     message.
1658         options  -- Must be zero for now.
1659
1660         """
1661         lck = self._lib().auto_lock()
1662         err = _pjsua.call_xfer_replaces(self._id, call._id, options,
1663                                           Lib._create_msg_data(hdr_list))
1664         self._lib()._err_check("transfer_to_call()", self, err)
1665
1666     def dial_dtmf(self, digits):
1667         """
1668         Send DTMF digits with RTP event package.
1669
1670         Keyword arguments:
1671         digits  -- DTMF digit string.
1672
1673         """
1674         lck = self._lib().auto_lock()
1675         err = _pjsua.call_dial_dtmf(self._id, digits)
1676         self._lib()._err_check("dial_dtmf()", self, err)
1677
1678     def send_request(self, method, hdr_list=None, content_type=None,
1679                      body=None):
1680         """
1681         Send arbitrary request to remote call. 
1682         
1683         This is useful for example to send INFO request. Note that this 
1684         function should not be used to send request that will change the 
1685         call state such as CANCEL or BYE.
1686
1687         Keyword arguments:
1688         method       -- SIP method name.
1689         hdr_list     -- Optional header list to be sent with the request.
1690         content_type -- Content type to describe the body, if the body
1691                         is present
1692         body         -- Optional SIP message body.
1693
1694         """
1695         lck = self._lib().auto_lock()
1696         if hdr_list or body:
1697             msg_data = _pjsua.Msg_Data()
1698             if hdr_list:
1699                 msg_data.hdr_list = hdr_list
1700             if content_type:
1701                 msg_data.content_type = content_type
1702             if body:
1703                 msg_data.msg_body = body
1704         else:
1705             msg_data = None
1706                 
1707         err = _pjsua.call_send_request(self._id, method, msg_data)
1708         self._lib()._err_check("send_request()", self, err)
1709
1710     def send_pager(self, text, im_id=0, content_type="text/plain", 
1711                    hdr_list=None):
1712         """Send instant message inside a call.
1713
1714         Keyword arguments:
1715         text         -- Instant message to be sent
1716         im_id        -- Optional instant message ID to identify this
1717                         instant message when delivery status callback
1718                         is called.
1719         content_type -- MIME type identifying the instant message
1720         hdr_list     -- Optional list of headers to be sent with the
1721                         request.
1722
1723         """
1724         lck = self._lib().auto_lock()
1725         err = _pjsua.call_send_im(self._id, \
1726                              content_type, text, \
1727                              Lib._create_msg_data(hdr_list), \
1728                              im_id)
1729         self._lib()._err_check("send_pager()", self, err)
1730
1731   
1732 class BuddyInfo:
1733     """This class contains information about Buddy. Application may 
1734     retrieve this information by calling Buddy.info().
1735
1736     Member documentation:
1737
1738     uri             -- the Buddy URI.
1739     contact         -- the Buddy Contact URI, if available.
1740     online_status   -- the presence online status.
1741     online_text     -- the presence online status text.
1742     activity        -- the PresenceActivity
1743     subscribed      -- specify whether buddy's presence status is currently
1744                        being subscribed.
1745     sub_state       -- SubscriptionState
1746     sub_term_reason -- The termination reason string of the last presence
1747                        subscription to this buddy, if any.
1748     """
1749     uri = ""
1750     contact = ""
1751     online_status = 0
1752     online_text = ""
1753     activity = PresenceActivity.UNKNOWN
1754     subscribed = False
1755     sub_state = SubscriptionState.NULL
1756     sub_term_reason = ""
1757
1758     def __init__(self, pjsua_bi=None):
1759         if pjsua_bi:
1760             self._cvt_from_pjsua(pjsua_bi)
1761
1762     def _cvt_from_pjsua(self, inf):
1763         self.uri = inf.uri
1764         self.contact = inf.contact
1765         self.online_status = inf.status
1766         self.online_text = inf.status_text
1767         self.activity = inf.activity
1768         self.subscribed = inf.monitor_pres
1769         self.sub_state = inf.sub_state
1770         self.sub_term_reason = inf.sub_term_reason
1771
1772
1773 class BuddyCallback:
1774     """This class can be used to receive notifications about Buddy's
1775     presence status change. Application needs to derive a class from
1776     this class, and register the instance with Buddy.set_callback().
1777
1778     Member documentation:
1779
1780     buddy   -- the Buddy object.
1781     """
1782     buddy = None
1783
1784     def __init__(self, buddy=None):
1785         self._set_buddy(buddy)
1786
1787     def _set_buddy(self, buddy):
1788         if buddy:
1789             self.buddy = weakref.proxy(buddy)
1790         else:
1791             self.buddy = None
1792
1793     def on_state(self):
1794         """
1795         Notification that buddy's presence state has changed. Application
1796         may then retrieve the new status with Buddy.info() function.
1797         """
1798         pass
1799    
1800     def on_pager(self, mime_type, body):
1801         """Notification that incoming instant message is received from
1802         this buddy.
1803
1804         Keyword arguments:
1805         mime_type  -- MIME type of the instant message body
1806         body       -- the instant message body
1807
1808         """
1809         pass
1810
1811     def on_pager_status(self, body, im_id, code, reason):
1812         """Notification about the delivery status of previously sent
1813         instant message.
1814
1815         Keyword arguments:
1816         body    -- the message body
1817         im_id   -- message ID
1818         code    -- SIP status code
1819         reason  -- SIP reason phrase
1820
1821         """
1822         pass
1823
1824     def on_typing(self, is_typing):
1825         """Notification that remote is typing or stop typing.
1826
1827         Keyword arguments:
1828         is_typing -- boolean to indicate whether remote is currently
1829                      typing an instant message.
1830
1831         """
1832         pass
1833
1834
1835 class Buddy:
1836     """A Buddy represents person or remote agent.
1837
1838     This class provides functions to subscribe to buddy's presence and
1839     to send or receive instant messages from the buddy.
1840     """
1841     _id = -1
1842     _lib = None
1843     _cb = None
1844     _obj_name = ""
1845     _acc = None
1846
1847     def __init__(self, lib, id, account, cb):
1848         self._id = id
1849         self._lib = weakref.ref(lib)
1850         self._acc = weakref.ref(account)
1851         self._obj_name = "{Buddy " + self.info().uri + "}"
1852         self.set_callback(cb)
1853         _pjsua.buddy_set_user_data(self._id, self)
1854         _Trace((self, 'created'))
1855
1856     def __del__(self):
1857         if self._id != -1:
1858             _pjsua.buddy_set_user_data(self._id, 0)
1859         _Trace((self, 'destroyed'))
1860
1861     def __str__(self):
1862         return self._obj_name
1863
1864     def info(self):
1865         """
1866         Get buddy info as BuddyInfo.
1867         """
1868         lck = self._lib().auto_lock()
1869         return BuddyInfo(_pjsua.buddy_get_info(self._id))
1870
1871     def set_callback(self, cb):
1872         """Install callback to receive notifications from this object.
1873
1874         Keyword argument:
1875         cb  -- BuddyCallback instance.
1876         """
1877         if cb:
1878             self._cb = cb
1879         else:
1880             self._cb = BuddyCallback(self)
1881         self._cb._set_buddy(self)
1882
1883     def subscribe(self):
1884         """
1885         Subscribe to buddy's presence status notification.
1886         """
1887         lck = self._lib().auto_lock()
1888         err = _pjsua.buddy_subscribe_pres(self._id, True)
1889         self._lib()._err_check("subscribe()", self, err)
1890
1891     def unsubscribe(self):
1892         """
1893         Unsubscribe from buddy's presence status notification.
1894         """
1895         lck = self._lib().auto_lock()
1896         err = _pjsua.buddy_subscribe_pres(self._id, False)
1897         self._lib()._err_check("unsubscribe()", self, err)
1898
1899     def delete(self):
1900         """
1901         Remove this buddy from the buddy list.
1902         """
1903         lck = self._lib().auto_lock()
1904         if self._id != -1:
1905             _pjsua.buddy_set_user_data(self._id, 0)
1906         err = _pjsua.buddy_del(self._id)
1907         self._lib()._err_check("delete()", self, err)
1908
1909     def send_pager(self, text, im_id=0, content_type="text/plain", \
1910                    hdr_list=None):
1911         """Send instant message to remote buddy.
1912
1913         Keyword arguments:
1914         text         -- Instant message to be sent
1915         im_id        -- Optional instant message ID to identify this
1916                         instant message when delivery status callback
1917                         is called.
1918         content_type -- MIME type identifying the instant message
1919         hdr_list     -- Optional list of headers to be sent with the
1920                         request.
1921
1922         """
1923         lck = self._lib().auto_lock()
1924         err = _pjsua.im_send(self._acc()._id, self.info().uri, \
1925                              content_type, text, \
1926                              Lib._create_msg_data(hdr_list), \
1927                              im_id)
1928         self._lib()._err_check("send_pager()", self, err)
1929
1930     def send_typing_ind(self, is_typing=True, hdr_list=None):
1931         """Send typing indication to remote buddy.
1932
1933         Keyword argument:
1934         is_typing -- boolean to indicate wheter user is typing.
1935         hdr_list  -- Optional list of headers to be sent with the
1936                      request.
1937
1938         """
1939         lck = self._lib().auto_lock()
1940         err = _pjsua.im_typing(self._acc()._id, self.info().uri, \
1941                                is_typing, Lib._create_msg_data(hdr_list))
1942         self._lib()._err_check("send_typing_ind()", self, err)
1943
1944
1945
1946 # Sound device info
1947 class SoundDeviceInfo:
1948     """This described the sound device info.
1949
1950     Member documentation:
1951     name                -- device name.
1952     input_channels      -- number of capture channels supported.
1953     output_channels     -- number of playback channels supported.
1954     default_clock_rate  -- default sampling rate.
1955     """
1956     name = ""
1957     input_channels = 0
1958     output_channels = 0
1959     default_clock_rate = 0
1960
1961     def __init__(self, sdi):
1962         self.name = sdi.name
1963         self.input_channels = sdi.input_count
1964         self.output_channels = sdi.output_count
1965         self.default_clock_rate = sdi.default_samples_per_sec
1966
1967
1968 # Codec info
1969 class CodecInfo:
1970     """This describes codec info.
1971
1972     Member documentation:
1973     name            -- codec name
1974     priority        -- codec priority (0-255)
1975     clock_rate      -- clock rate
1976     channel_count   -- number of channels
1977     avg_bps         -- average bandwidth in bits per second
1978     frm_ptime       -- base frame length in milliseconds
1979     ptime           -- RTP frame length in milliseconds.
1980     pt              -- payload type.
1981     vad_enabled     -- specify if Voice Activity Detection is currently
1982                        enabled.
1983     plc_enabled     -- specify if Packet Lost Concealment is currently
1984                        enabled.
1985     """
1986     name = ""
1987     priority = 0
1988     clock_rate = 0
1989     channel_count = 0
1990     avg_bps = 0
1991     frm_ptime = 0
1992     ptime = 0
1993     pt = 0
1994     vad_enabled = False
1995     plc_enabled = False
1996
1997     def __init__(self, codec_info, codec_param):
1998         self.name = codec_info.codec_id
1999         self.priority = codec_info.priority
2000         self.clock_rate = codec_param.info.clock_rate
2001         self.channel_count = codec_param.info.channel_cnt
2002         self.avg_bps = codec_param.info.avg_bps
2003         self.frm_ptime = codec_param.info.frm_ptime
2004         self.ptime = codec_param.info.frm_ptime * \
2005                         codec_param.setting.frm_per_pkt
2006         self.ptime = codec_param.info.pt
2007         self.vad_enabled = codec_param.setting.vad
2008         self.plc_enabled = codec_param.setting.plc
2009
2010     def _cvt_to_pjsua(self):
2011         ci = _pjsua.Codec_Info()
2012         ci.codec_id = self.name
2013         ci.priority = self.priority
2014         return ci
2015
2016
2017 # Codec parameter
2018 class CodecParameter:
2019     """This specifies various parameters that can be configured for codec.
2020
2021     Member documentation:
2022
2023     ptime       -- specify the outgoing RTP packet length in milliseconds.
2024     vad_enabled -- specify if VAD should be enabled.
2025     plc_enabled -- specify if PLC should be enabled.
2026     """
2027     ptime = 0
2028     vad_enabled = False
2029     plc_enabled = False
2030     _codec_param = None
2031     
2032     def __init__(self, codec_param):
2033         self.ptime = codec_param.info.frm_ptime * \
2034                         codec_param.setting.frm_per_pkt
2035         self.vad_enabled = codec_param.setting.vad
2036         self.plc_enabled = codec_param.setting.plc
2037         self._codec_param = codec_param
2038
2039     def _cvt_to_pjsua(self):
2040         self._codec_param.setting.frm_per_pkt = self.ptime / \
2041                                                 self._codec_param.info.frm_ptime
2042         self._codec_param.setting.vad = self.vad_enabled
2043         self._codec_param.setting.plc = self.plc_enabled
2044         return self._codec_param
2045
2046
2047 # Library mutex
2048 class _LibMutex:
2049     def __init__(self, lck):
2050         self._lck = lck
2051         self._lck.acquire()
2052         #_Trace(('lock acquired',))
2053
2054     def __del__(self):
2055         try:
2056             self._lck.release()
2057             #_Trace(('lock released',))
2058         except:
2059             #_Trace(('lock release error',))
2060             pass
2061
2062
2063 # PJSUA Library
2064 _lib = None
2065 enable_trace = False
2066
2067 class Lib:
2068     """Library instance.
2069     
2070     """
2071     _quit = False
2072     _has_thread = False
2073     _lock = None
2074
2075     def __init__(self):
2076         global _lib
2077         if _lib:
2078             raise Error("__init()__", None, -1, 
2079                         "Library instance already exist")
2080
2081         self._lock = threading.RLock()
2082         err = _pjsua.create()
2083         self._err_check("_pjsua.create()", None, err)
2084         _lib = self
2085
2086     def __del__(self):
2087         _pjsua.destroy()
2088         del self._lock
2089         _Trace(('Lib destroyed',))
2090
2091     def __str__(self):
2092         return "Lib"
2093
2094     @staticmethod
2095     def instance():
2096         """Return singleton instance of Lib.
2097         """
2098         return _lib
2099
2100     def init(self, ua_cfg=None, log_cfg=None, media_cfg=None):
2101         """
2102         Initialize pjsua with the specified configurations.
2103
2104         Keyword arguments:
2105         ua_cfg      -- optional UAConfig instance
2106         log_cfg     -- optional LogConfig instance
2107         media_cfg   -- optional MediaConfig instance
2108
2109         """
2110         if not ua_cfg: ua_cfg = UAConfig()
2111         if not log_cfg: log_cfg = LogConfig()
2112         if not media_cfg: media_cfg = MediaConfig()
2113
2114         py_ua_cfg = ua_cfg._cvt_to_pjsua()
2115         py_ua_cfg.cb.on_call_state = _cb_on_call_state
2116         py_ua_cfg.cb.on_incoming_call = _cb_on_incoming_call
2117         py_ua_cfg.cb.on_call_media_state = _cb_on_call_media_state
2118         py_ua_cfg.cb.on_dtmf_digit = _cb_on_dtmf_digit
2119         py_ua_cfg.cb.on_call_transfer_request = _cb_on_call_transfer_request
2120         py_ua_cfg.cb.on_call_transfer_status = _cb_on_call_transfer_status
2121         py_ua_cfg.cb.on_call_replace_request = _cb_on_call_replace_request
2122         py_ua_cfg.cb.on_call_replaced = _cb_on_call_replaced
2123         py_ua_cfg.cb.on_reg_state = _cb_on_reg_state
2124         py_ua_cfg.cb.on_incoming_subscribe = _cb_on_incoming_subscribe
2125         py_ua_cfg.cb.on_buddy_state = _cb_on_buddy_state
2126         py_ua_cfg.cb.on_pager = _cb_on_pager
2127         py_ua_cfg.cb.on_pager_status = _cb_on_pager_status
2128         py_ua_cfg.cb.on_typing = _cb_on_typing
2129         py_ua_cfg.cb.on_mwi_info = _cb_on_mwi_info;
2130
2131         err = _pjsua.init(py_ua_cfg, log_cfg._cvt_to_pjsua(), 
2132                           media_cfg._cvt_to_pjsua())
2133         self._err_check("init()", self, err)
2134
2135     def destroy(self):
2136         """Destroy the library, and pjsua."""
2137         global _lib
2138         if self._has_thread:
2139             self._quit = 1
2140             loop = 0
2141             while self._quit != 2 and loop < 400:
2142                 self.handle_events(5)
2143                 loop = loop + 1
2144                 time.sleep(0.050)
2145         _pjsua.destroy()
2146         _lib = None
2147
2148     def start(self, with_thread=True):
2149         """Start the library. 
2150
2151         Keyword argument:
2152         with_thread -- specify whether the module should create worker
2153                        thread.
2154
2155         """
2156         lck = self.auto_lock()
2157         err = _pjsua.start()
2158         self._err_check("start()", self, err)
2159         self._has_thread = with_thread
2160         if self._has_thread:
2161             thread.start_new(_worker_thread_main, (0,))
2162
2163     def handle_events(self, timeout=50):
2164         """Poll the events from underlying pjsua library.
2165         
2166         Application must poll the stack periodically if worker thread
2167         is disable when starting the library.
2168
2169         Keyword argument:
2170         timeout -- in milliseconds.
2171
2172         """
2173         lck = self.auto_lock()
2174         return _pjsua.handle_events(timeout)
2175
2176     def thread_register(self, name):
2177         """Register external threads (threads that are not created by PJSIP,
2178         such as threads that are created by Python API) to PJSIP.
2179
2180         The call must be made from the new thread before calling any pjlib 
2181         functions.
2182
2183         Keyword arguments:
2184         name    -- Non descriptive name for the thread
2185         """
2186         dummy = 1
2187         err = _pjsua.thread_register(name, dummy)
2188         self._err_check("thread_register()", self, err)
2189
2190     def verify_sip_url(self, sip_url):
2191         """Verify that the specified string is a valid URI. 
2192         
2193         Keyword argument:
2194         sip_url -- the URL string.
2195         
2196         Return:
2197             0 is the the URI is valid, otherwise the appropriate error 
2198             code is returned.
2199
2200         """
2201         lck = self.auto_lock()
2202         return _pjsua.verify_sip_url(sip_url)
2203
2204     def create_transport(self, type, cfg=None):
2205         """Create SIP transport instance of the specified type. 
2206         
2207         Keyword arguments:
2208         type    -- transport type from TransportType constant.
2209         cfg     -- TransportConfig instance
2210
2211         Return:
2212             Transport object
2213
2214         """
2215         lck = self.auto_lock()
2216         if not cfg: cfg=TransportConfig()
2217         err, tp_id = _pjsua.transport_create(type, cfg._cvt_to_pjsua())
2218         self._err_check("create_transport()", self, err)
2219         return Transport(self, tp_id)
2220
2221     def create_account(self, acc_config, set_default=True, cb=None):
2222         """
2223         Create a new local pjsua account using the specified configuration.
2224
2225         Keyword arguments:
2226         acc_config  -- AccountConfig
2227         set_default -- boolean to specify whether to use this as the
2228                        default account.
2229         cb          -- AccountCallback instance.
2230
2231         Return:
2232             Account instance
2233
2234         """
2235         lck = self.auto_lock()
2236         err, acc_id = _pjsua.acc_add(acc_config._cvt_to_pjsua(), set_default)
2237         self._err_check("create_account()", self, err)
2238         return Account(self, acc_id, cb)
2239
2240     def create_account_for_transport(self, transport, set_default=True,
2241                                      cb=None):
2242         """Create a new local pjsua transport for the specified transport.
2243
2244         Keyword arguments:
2245         transport   -- the Transport instance.
2246         set_default -- boolean to specify whether to use this as the
2247                        default account.
2248         cb          -- AccountCallback instance.
2249
2250         Return:
2251             Account instance
2252
2253         """
2254         lck = self.auto_lock()
2255         err, acc_id = _pjsua.acc_add_local(transport._id, set_default)
2256         self._err_check("create_account_for_transport()", self, err)
2257         return Account(self, acc_id, cb)
2258
2259     def hangup_all(self):
2260         """Hangup all calls.
2261
2262         """
2263         lck = self.auto_lock()
2264         _pjsua.call_hangup_all()
2265
2266     # Sound device API
2267
2268     def enum_snd_dev(self):
2269         """Enumerate sound devices in the system.
2270
2271         Return:
2272             list of SoundDeviceInfo. The index of the element specifies
2273             the device ID for the device.
2274         """
2275         lck = self.auto_lock()
2276         sdi_list = _pjsua.enum_snd_devs()
2277         info = []
2278         for sdi in sdi_list:
2279             info.append(SoundDeviceInfo(sdi))
2280         return info
2281
2282     def get_snd_dev(self):
2283         """Get the device IDs of current sound devices used by pjsua.
2284
2285         Return:
2286             (capture_dev_id, playback_dev_id) tuple
2287         """
2288         lck = self.auto_lock()
2289         return _pjsua.get_snd_dev()
2290
2291     def set_snd_dev(self, capture_dev, playback_dev):
2292         """Change the current sound devices.
2293
2294         Keyword arguments:
2295         capture_dev  -- the device ID of capture device to be used
2296         playback_dev -- the device ID of playback device to be used.
2297
2298         """
2299         lck = self.auto_lock()
2300         err = _pjsua.set_snd_dev(capture_dev, playback_dev)
2301         self._err_check("set_current_sound_devices()", self, err)
2302     
2303     def set_null_snd_dev(self):
2304         """Disable the sound devices. This is useful if the system
2305         does not have sound device installed.
2306
2307         """
2308         lck = self.auto_lock()
2309         err = _pjsua.set_null_snd_dev()
2310         self._err_check("set_null_snd_dev()", self, err)
2311
2312     
2313     # Conference bridge
2314
2315     def conf_get_max_ports(self):
2316         """Get the conference bridge capacity.
2317
2318         Return:
2319             conference bridge capacity.
2320
2321         """
2322         lck = self.auto_lock()
2323         return _pjsua.conf_get_max_ports()
2324
2325     def conf_connect(self, src_slot, dst_slot):
2326         """Establish unidirectional media flow from souce to sink. 
2327         
2328         One source may transmit to multiple destinations/sink. And if 
2329         multiple sources are transmitting to the same sink, the media 
2330         will be mixed together. Source and sink may refer to the same ID, 
2331         effectively looping the media.
2332
2333         If bidirectional media flow is desired, application needs to call
2334         this function twice, with the second one having the arguments 
2335         reversed.
2336
2337         Keyword arguments:
2338         src_slot    -- integer to identify the conference slot number of
2339                        the source/transmitter.
2340         dst_slot    -- integer to identify the conference slot number of    
2341                        the destination/receiver.
2342
2343         """
2344         lck = self.auto_lock()
2345         err = _pjsua.conf_connect(src_slot, dst_slot)
2346         self._err_check("conf_connect()", self, err)
2347     
2348     def conf_disconnect(self, src_slot, dst_slot):
2349         """Disconnect media flow from the source to destination port.
2350
2351         Keyword arguments:
2352         src_slot    -- integer to identify the conference slot number of
2353                        the source/transmitter.
2354         dst_slot    -- integer to identify the conference slot number of    
2355                        the destination/receiver.
2356
2357         """
2358         lck = self.auto_lock()
2359         err = _pjsua.conf_disconnect(src_slot, dst_slot)
2360         self._err_check("conf_disconnect()", self, err)
2361
2362     def conf_set_tx_level(self, slot, level):
2363         """Adjust the signal level to be transmitted from the bridge to 
2364         the specified port by making it louder or quieter.
2365
2366         Keyword arguments:
2367         slot        -- integer to identify the conference slot number.
2368         level       -- Signal level adjustment. Value 1.0 means no level
2369                        adjustment, while value 0 means to mute the port.
2370         """
2371         lck = self.auto_lock()
2372         err = _pjsua.conf_set_tx_level(slot, level)
2373         self._err_check("conf_set_tx_level()", self, err)
2374         
2375     def conf_set_rx_level(self, slot, level):
2376         """Adjust the signal level to be received from the specified port
2377         (to the bridge) by making it louder or quieter.
2378
2379         Keyword arguments:
2380         slot        -- integer to identify the conference slot number.
2381         level       -- Signal level adjustment. Value 1.0 means no level
2382                        adjustment, while value 0 means to mute the port.
2383         """
2384         lck = self.auto_lock()
2385         err = _pjsua.conf_set_rx_level(slot, level)
2386         self._err_check("conf_set_rx_level()", self, err)
2387         
2388     def conf_get_signal_level(self, slot):
2389         """Get last signal level transmitted to or received from the 
2390         specified port. The signal levels are float values from 0.0 to 1.0,
2391         with 0.0 indicates no signal, and 1.0 indicates the loudest signal
2392         level.
2393
2394         Keyword arguments:
2395         slot        -- integer to identify the conference slot number.
2396
2397         Return value:
2398             (tx_level, rx_level) tuple.
2399         """
2400         lck = self.auto_lock()
2401         err, tx_level, rx_level = _pjsua.conf_get_signal_level(slot)
2402         self._err_check("conf_get_signal_level()", self, err)
2403         return (tx_level, rx_level)
2404         
2405
2406
2407     # Codecs API
2408
2409     def enum_codecs(self):
2410         """Return list of codecs supported by pjsua.
2411
2412         Return:
2413             list of CodecInfo
2414
2415         """
2416         lck = self.auto_lock()
2417         ci_list = _pjsua.enum_codecs()
2418         codec_info = []
2419         for ci in ci_list:
2420             cp = _pjsua.codec_get_param(ci.codec_id)
2421             if cp:
2422                 codec_info.append(CodecInfo(ci, cp))
2423         return codec_info
2424
2425     def set_codec_priority(self, name, priority):
2426         """Change the codec priority.
2427
2428         Keyword arguments:
2429         name     -- Codec name
2430         priority -- Codec priority, which range is 0-255.
2431
2432         """
2433         lck = self.auto_lock()
2434         err = _pjsua.codec_set_priority(name, priority)
2435         self._err_check("set_codec_priority()", self, err)
2436
2437     def get_codec_parameter(self, name):
2438         """Get codec parameter for the specified codec.
2439
2440         Keyword arguments:
2441         name    -- codec name.
2442
2443         """
2444         lck = self.auto_lock()
2445         cp = _pjsua.codec_get_param(name)
2446         if not cp:
2447             self._err_check("get_codec_parameter()", self, -1, 
2448                             "Invalid codec name")
2449         return CodecParameter(cp)
2450
2451     def set_codec_parameter(self, name, param):
2452         """Modify codec parameter for the specified codec.
2453
2454         Keyword arguments:
2455         name    -- codec name
2456         param   -- codec parameter.
2457
2458         """
2459         lck = self.auto_lock()
2460         err = _pjsua.codec_set_param(name, param._cvt_to_pjsua())
2461         self._err_check("set_codec_parameter()", self, err)
2462     
2463     # WAV playback and recording
2464
2465     def create_player(self, filename, loop=False):
2466         """Create WAV file player.
2467
2468         Keyword arguments
2469         filename    -- WAV file name
2470         loop        -- boolean to specify whether playback should
2471                        automatically restart upon EOF
2472         Return:
2473             WAV player ID
2474
2475         """
2476         lck = self.auto_lock()
2477         opt = 0
2478         if not loop:
2479             opt = opt + 1
2480         err, player_id = _pjsua.player_create(filename, opt)
2481         self._err_check("create_player()", self, err)
2482         return player_id
2483         
2484     def player_get_slot(self, player_id):
2485         """Get the conference port ID for the specified player.
2486
2487         Keyword arguments:
2488         player_id  -- the WAV player ID
2489         
2490         Return:
2491             Conference slot number for the player
2492
2493         """
2494         lck = self.auto_lock()
2495         slot = _pjsua.player_get_conf_port(player_id)
2496         if slot < 0:
2497                 self._err_check("player_get_slot()", self, -1, 
2498                                 "Invalid player id")
2499         return slot
2500
2501     def player_set_pos(self, player_id, pos):
2502         """Set WAV playback position.
2503
2504         Keyword arguments:
2505         player_id   -- WAV player ID
2506         pos         -- playback position, in samples
2507
2508         """
2509         lck = self.auto_lock()
2510         err = _pjsua.player_set_pos(player_id, pos)
2511         self._err_check("player_set_pos()", self, err)
2512         
2513     def player_destroy(self, player_id):
2514         """Destroy the WAV player.
2515
2516         Keyword arguments:
2517         player_id   -- the WAV player ID.
2518
2519         """
2520         lck = self.auto_lock()
2521         err = _pjsua.player_destroy(player_id)
2522         self._err_check("player_destroy()", self, err)
2523
2524     def create_playlist(self, filelist, label="playlist", loop=True):
2525         """Create WAV playlist.
2526
2527         Keyword arguments:
2528         filelist    -- List of WAV file names.
2529         label       -- Optional name to be assigned to the playlist
2530                        object (useful for logging)
2531         loop        -- boolean to specify whether playback should
2532                        automatically restart upon EOF
2533
2534         Return:
2535             playlist_id
2536         """
2537         lck = self.auto_lock()
2538         opt = 0
2539         if not loop:
2540             opt = opt + 1
2541         err, playlist_id = _pjsua.playlist_create(label, filelist, opt)
2542         self._err_check("create_playlist()", self, err)
2543         return playlist_id 
2544
2545     def playlist_get_slot(self, playlist_id):
2546         """Get the conference port ID for the specified playlist.
2547
2548         Keyword arguments:
2549         playlist_id  -- the WAV playlist ID
2550         
2551         Return:
2552             Conference slot number for the playlist
2553
2554         """
2555         lck = self.auto_lock()
2556         slot = _pjsua.player_get_conf_port(playlist_id)
2557         if slot < 0:
2558                 self._err_check("playlist_get_slot()", self, -1, 
2559                                 "Invalid playlist id")
2560         return slot
2561
2562     def playlist_destroy(self, playlist_id):
2563         """Destroy the WAV playlist.
2564
2565         Keyword arguments:
2566         playlist_id   -- the WAV playlist ID.
2567
2568         """
2569         lck = self.auto_lock()
2570         err = _pjsua.player_destroy(playlist_id)
2571         self._err_check("playlist_destroy()", self, err)
2572
2573     def create_recorder(self, filename):
2574         """Create WAV file recorder.
2575
2576         Keyword arguments
2577         filename    -- WAV file name
2578
2579         Return:
2580             WAV recorder ID
2581
2582         """
2583         lck = self.auto_lock()
2584         err, rec_id = _pjsua.recorder_create(filename, 0, None, -1, 0)
2585         self._err_check("create_recorder()", self, err)
2586         return rec_id
2587         
2588     def recorder_get_slot(self, rec_id):
2589         """Get the conference port ID for the specified recorder.
2590
2591         Keyword arguments:
2592         rec_id  -- the WAV recorder ID
2593         
2594         Return:
2595             Conference slot number for the recorder
2596
2597         """
2598         lck = self.auto_lock()
2599         slot = _pjsua.recorder_get_conf_port(rec_id)
2600         if slot < 1:
2601             self._err_check("recorder_get_slot()", self, -1, 
2602                             "Invalid recorder id")
2603         return slot
2604
2605     def recorder_destroy(self, rec_id):
2606         """Destroy the WAV recorder.
2607
2608         Keyword arguments:
2609         rec_id   -- the WAV recorder ID.
2610
2611         """
2612         lck = self.auto_lock()
2613         err = _pjsua.recorder_destroy(rec_id)
2614         self._err_check("recorder_destroy()", self, err)
2615
2616
2617     # Internal functions
2618
2619     @staticmethod
2620     def strerror(err):
2621         return _pjsua.strerror(err)
2622     
2623     def _err_check(self, op_name, obj, err_code, err_msg=""):
2624         if err_code != 0:
2625             raise Error(op_name, obj, err_code, err_msg)
2626
2627     @staticmethod
2628     def _create_msg_data(hdr_list):
2629         if not hdr_list:
2630             return None
2631         msg_data = _pjsua.Msg_Data()
2632         msg_data.hdr_list = hdr_list
2633         return msg_data
2634     
2635     def auto_lock(self):
2636         return _LibMutex(self._lock)
2637
2638     # Internal dictionary manipulation for calls, accounts, and buddies
2639
2640     def _lookup_call(self, call_id):
2641         return _pjsua.call_get_user_data(call_id)
2642
2643     def _lookup_account(self, acc_id):
2644         return _pjsua.acc_get_user_data(acc_id)
2645
2646     def _lookup_buddy(self, buddy_id, uri=None):
2647         if buddy_id != -1:
2648             buddy = _pjsua.buddy_get_user_data(buddy_id)
2649         elif uri:
2650             buddy_id = _pjsua.buddy_find(uri)
2651             if buddy_id != -1:
2652                 buddy = _pjsua.buddy_get_user_data(buddy_id)
2653             else:
2654                 buddy = None
2655         else:
2656             buddy = None
2657             
2658         return buddy 
2659
2660     # Account allbacks
2661
2662     def _cb_on_reg_state(self, acc_id):
2663         acc = self._lookup_account(acc_id)
2664         if acc:
2665             acc._cb.on_reg_state()
2666
2667     def _cb_on_incoming_subscribe(self, acc_id, buddy_id, from_uri, 
2668                                   contact_uri, pres_obj):
2669         acc = self._lookup_account(acc_id)
2670         if acc:
2671             buddy = self._lookup_buddy(buddy_id)
2672             return acc._cb.on_incoming_subscribe(buddy, from_uri, contact_uri,
2673                                                  pres_obj)
2674         else:
2675             return (404, None)
2676
2677     def _cb_on_incoming_call(self, acc_id, call_id, rdata):
2678         acc = self._lookup_account(acc_id)
2679         if acc:
2680             acc._cb.on_incoming_call( Call(self, call_id) )
2681         else:
2682             _pjsua.call_hangup(call_id, 603, None, None)
2683
2684     # Call callbacks 
2685
2686     def _cb_on_call_state(self, call_id):
2687         call = self._lookup_call(call_id)
2688         if call:
2689             if call._id == -1:
2690                 call.attach_to_id(call_id)
2691             done = (call.info().state == CallState.DISCONNECTED)
2692             call._cb.on_state()
2693             if done:
2694                 _pjsua.call_set_user_data(call_id, 0)
2695         else:
2696             pass
2697
2698     def _cb_on_call_media_state(self, call_id):
2699         call = self._lookup_call(call_id)
2700         if call:
2701             call._cb.on_media_state()
2702
2703     def _cb_on_dtmf_digit(self, call_id, digits):
2704         call = self._lookup_call(call_id)
2705         if call:
2706             call._cb.on_dtmf_digit(digits)
2707
2708     def _cb_on_call_transfer_request(self, call_id, dst, code):
2709         call = self._lookup_call(call_id)
2710         if call:
2711             return call._cb.on_transfer_request(dst, code)
2712         else:
2713             return 603
2714
2715     def _cb_on_call_transfer_status(self, call_id, code, text, final, cont):
2716         call = self._lookup_call(call_id)
2717         if call:
2718             return call._cb.on_transfer_status(code, text, final, cont)
2719         else:
2720             return cont
2721
2722     def _cb_on_call_replace_request(self, call_id, rdata, code, reason):
2723         call = self._lookup_call(call_id)
2724         if call:
2725             return call._cb.on_replace_request(code, reason)
2726         else:
2727             return code, reason
2728
2729     def _cb_on_call_replaced(self, old_call_id, new_call_id):
2730         old_call = self._lookup_call(old_call_id)
2731         new_call = self._lookup_call(new_call_id)
2732         if old_call and new_call:
2733             old_call._cb.on_replaced(new_call)
2734
2735     def _cb_on_pager(self, call_id, from_uri, to_uri, contact, mime_type, 
2736                      body, acc_id):
2737         call = None
2738         if call_id != -1:
2739             call = self._lookup_call(call_id)
2740         if call:
2741             call._cb.on_pager(mime_type, body)
2742         else:
2743             acc = self._lookup_account(acc_id)
2744             buddy = self._lookup_buddy(-1, from_uri)
2745             if buddy:
2746                 buddy._cb.on_pager(mime_type, body)
2747             else:
2748                 acc._cb.on_pager(from_uri, contact, mime_type, body)
2749
2750     def _cb_on_pager_status(self, call_id, to_uri, body, user_data, 
2751                             code, reason, acc_id):
2752         call = None
2753         if call_id != -1:
2754             call = self._lookup_call(call_id)
2755         if call:
2756             call._cb.on_pager_status(body, user_data, code, reason)
2757         else:
2758             acc = self._lookup_account(acc_id)
2759             buddy = self._lookup_buddy(-1, to_uri)
2760             if buddy:
2761                 buddy._cb.on_pager_status(body, user_data, code, reason)
2762             else:
2763                 acc._cb.on_pager_status(to_uri, body, user_data, code, reason)
2764
2765     def _cb_on_typing(self, call_id, from_uri, to_uri, contact, is_typing, 
2766                       acc_id):
2767         call = None
2768         if call_id != -1:
2769             call = self._lookup_call(call_id)
2770         if call:
2771             call._cb.on_typing(is_typing)
2772         else:
2773             acc = self._lookup_account(acc_id)
2774             buddy = self._lookup_buddy(-1, from_uri)
2775             if buddy:
2776                 buddy._cb.on_typing(is_typing)
2777             else:
2778                 acc._cb.on_typing(from_uri, contact, is_typing)
2779
2780     def _cb_on_mwi_info(self, acc_id, body):
2781         acc = self._lookup_account(acc_id)
2782         if acc:
2783             return acc._cb.on_mwi_info(body)
2784
2785     def _cb_on_buddy_state(self, buddy_id):
2786         buddy = self._lookup_buddy(buddy_id)
2787         if buddy:
2788             buddy._cb.on_state()
2789
2790 #
2791 # Internal
2792 #
2793
2794 def _cb_on_call_state(call_id, e):
2795     _lib._cb_on_call_state(call_id)
2796
2797 def _cb_on_incoming_call(acc_id, call_id, rdata):
2798     _lib._cb_on_incoming_call(acc_id, call_id, rdata)
2799
2800 def _cb_on_call_media_state(call_id):
2801     _lib._cb_on_call_media_state(call_id)
2802
2803 def _cb_on_dtmf_digit(call_id, digits):
2804     _lib._cb_on_dtmf_digit(call_id, digits)
2805
2806 def _cb_on_call_transfer_request(call_id, dst, code):
2807     return _lib._cb_on_call_transfer_request(call_id, dst, code)
2808
2809 def _cb_on_call_transfer_status(call_id, code, reason, final, cont):
2810     return _lib._cb_on_call_transfer_status(call_id, code, reason, 
2811                                              final, cont)
2812 def _cb_on_call_replace_request(call_id, rdata, code, reason):
2813     return _lib._cb_on_call_replace_request(call_id, rdata, code, reason)
2814
2815 def _cb_on_call_replaced(old_call_id, new_call_id):
2816     _lib._cb_on_call_replaced(old_call_id, new_call_id)
2817
2818 def _cb_on_reg_state(acc_id):
2819     _lib._cb_on_reg_state(acc_id)
2820
2821 def _cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, contact_uri, pres):
2822     return _lib._cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, 
2823                                           contact_uri, pres)
2824
2825 def _cb_on_buddy_state(buddy_id):
2826     _lib._cb_on_buddy_state(buddy_id)
2827
2828 def _cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id):
2829     _lib._cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id)
2830
2831 def _cb_on_pager_status(call_id, to, body, user_data, status, reason, acc_id):
2832     _lib._cb_on_pager_status(call_id, to, body, user_data, 
2833                              status, reason, acc_id)
2834
2835 def _cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id):
2836     _lib._cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id)
2837
2838 def _cb_on_mwi_info(acc_id, body):
2839     _lib._cb_on_mwi_info(acc_id, body)
2840
2841 # Worker thread
2842 def _worker_thread_main(arg):
2843     global _lib
2844     _Trace(('worker thread started..',))
2845     thread_desc = 0;
2846     err = _pjsua.thread_register("python worker", thread_desc)
2847     _lib._err_check("thread_register()", _lib, err)
2848     while _lib and _lib._quit == 0:
2849         _lib.handle_events(1)
2850         time.sleep(0.050)
2851     if _lib:
2852         _lib._quit = 2
2853     _Trace(('worker thread exited..',))
2854
2855 def _Trace(args):
2856     global enable_trace
2857     if enable_trace:
2858         print "** ",
2859         for arg in args:
2860             print arg,
2861         print " **"
2862