~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjsip-apps/src/python/pjsua.py

  • Committer: Package Import Robot
  • Author(s): Francois Marier, Francois Marier, Mark Purcell
  • Date: 2014-10-18 15:08:50 UTC
  • mfrom: (1.1.12)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20141018150850-2exfk34ckb15pcwi
Tags: 1.4.1-0.1
[ Francois Marier ]
* Non-maintainer upload
* New upstream release (closes: #759576, #741130)
  - debian/rules +PJPROJECT_VERSION := 2.2.1
  - add upstream patch to fix broken TLS support
  - add patch to fix pjproject regression

[ Mark Purcell ]
* Build-Depends:
  - sflphone-daemon + libavformat-dev, libavcodec-dev, libswscale-dev,
  libavdevice-dev, libavutil-dev
  - sflphone-gnome + libclutter-gtk-1.0-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# $Id: pjsua.py 2976 2009-10-29 08:16:46Z bennylp $
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