blob: 4d637da6676e0de3b472c54584c23c908acd3e1e [file] [log] [blame]
Benny Prijonob85ba652008-07-11 00:55:22 +00001# $Id$
Benny Prijono9c461142008-07-10 22:41:20 +00002#
3# Object oriented PJSUA wrapper.
4#
5# Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6#
7
8"""Multimedia communication client library based on SIP protocol.
9
10This implements a fully featured multimedia communication client
11library based on PJSIP stack (http://www.pjsip.org)
12
13
Benny Prijono288d4bd2008-07-19 15:40:21 +0000141. FEATURES
Benny Prijono9c461142008-07-10 22:41:20 +000015
Benny Prijono288d4bd2008-07-19 15:40:21 +000016 - Session Initiation Protocol (SIP) features:
Benny Prijono9c461142008-07-10 22:41:20 +000017 - Basic registration and call
18 - Multiple accounts
19 - Call hold, attended and unattended call transfer
20 - Presence
21 - Instant messaging
Benny Prijono288d4bd2008-07-19 15:40:21 +000022 - Multiple SIP accounts
23 - Media features:
Benny Prijono9c461142008-07-10 22:41:20 +000024 - Audio
25 - Conferencing
26 - Narrowband and wideband
27 - Codecs: PCMA, PCMU, GSM, iLBC, Speex, G.722, L16
28 - RTP/RTCP
Benny Prijono288d4bd2008-07-19 15:40:21 +000029 - Secure RTP (SRTP)
30 - WAV playback, recording, and playlist
Benny Prijono9c461142008-07-10 22:41:20 +000031 - NAT traversal features
32 - Symmetric RTP
33 - STUN
34 - TURN
35 - ICE
36
37
Benny Prijono288d4bd2008-07-19 15:40:21 +0000382. USING
39
40See http://www.pjsip.org/trac/wiki/Python_SIP_Tutorial for a more thorough
41tutorial. The paragraphs below explain basic tasks on using this module.
42
43
442.1 Initialization
45
46Instantiate Lib class. This class is a singleton class, there can only be
47one instance of this class in the program.
48
49Initialize the library with lib.init() method, and optionally specify various
50settings like UAConfig, MediaConfig, and LogConfig.
51
52Create one or more SIP Transport instances.
53
54Create one or more SIP Account's instances, as explained below.
55
56Once initialization is complete, call lib.start().
57
58
592.2 Accounts
60
61At least one Account must be created in the program. Use Lib's create_account()
62or create_account_for_transport() to create the account instance.
63
64Account may emit events, and to capture these events, application must derive
65a class from AccountCallback class, and install the callback to the Account
66instance using set_callback() method.
67
68
692.3 Calls
70
71Calls are represented with Call class. Use the Call methods to operate the
72call. Outgoing calls are made with make_call() method of Account class.
73Incoming calls are reported by on_incoming_call() callback of AccountCallback
74class.
75
76Call may emit events, and to capture these events, application must derive
77a class from CallCallback class, and install the callback to the Call instance
78using set_callback() method.
79
80Note that just like every other operations in this module, the make_call()
81method is non-blocking (i.e. it doesn't wait until the call is established
82before the function returns). Progress to the Call is reported via CallCallback
83class above.
84
85
862.4 Media
87
88Every objects that can transmit or receive media/audio (e.g. calls, WAV player,
89WAV recorder, WAV playlist) are connected to a central conference bridge.
90Application can use the object's method or Lib's method to retrieve the slot
91number of that particular object in the conference bridge:
92 - to retrieve the slot number of a call, use Call.info().conf_slot
93 - to retrieve the slot number of a WAV player, use Lib.player_get_slot()
94 - to retrieve the slot number of a WAV recorder, use Lib.recorder_get_slot()
95 - to retrieve the slot number of a playlist, use Lib.playlist_get_slot()
96 - the slot number zero is used to identity the sound device.
97
98The conference bridge provides powerful switching and mixing functionality
99for application. With the conference bridge, each conference slot (e.g.
100a call) can transmit to multiple destinations, and one destination can
101receive from multiple sources. If more than one media terminations are
102terminated in the same slot, the conference bridge will mix the signal
103automatically.
104
105Application connects one media termination/slot to another by calling
106lib.conf_connect() method. This will establish unidirectional media flow from
107the source termination to the sink termination. To establish bidirectional
108media flow, application would need to make another call to lib/conf_connect(),
109this time inverting the source and destination slots in the parameter.
110
111
1122.5 Presence
113
114To subscribe to presence information of a buddy, add Buddy object with
115add_buddy() method of Account class. Subsequent presence information for that
116Buddy will be reported via BuddyCallback class (which application should
117device and install to the Buddy object).
118
119Each Account has presence status associated with it, which will be informed
120to remote buddies when they subscribe to our presence information. Incoming
121presence subscription request by default will be accepted automatically,
122unless on_incoming_subscribe() method of AccountCallback is implemented.
123
124
1252.6 Instant Messaging
126
127Use Buddy's send_pager() and send_typing_ind() to send instant message and
128typing indication to the specified buddy.
129
130Incoming instant messages and typing indications will be reported via one of
131the three mechanisms below.
132
133If the instant message or typing indication is received in the context of an
134active call, then it will be reported via on_pager() or on_typing() method
135of CallCallback class.
136
137If the instant message or typing indication is received outside any call
138contexts, and it is received from a registered buddy, then it will be reported
139via on_pager() or on_typing() method of BuddyCallback class.
140
141If the criterias above are not met, the instant message or typing indication
142will be reported via on_pager() or on_typing() method of the AccountCallback
143class.
144
145The delivery status of outgoing instant messages are reported via
146on_pager_status() method of CallCallback, BuddyCallback, or AccountCallback,
147depending on whether the instant message was sent using Call, Buddy, or
148Account's send_pager() method.
149
Benny Prijono9c461142008-07-10 22:41:20 +0000150"""
151import _pjsua
152import thread
Benny Prijono55040452008-07-21 18:20:57 +0000153import threading
154import weakref
Benny Prijono6ecef072008-07-21 22:46:35 +0000155import time
Benny Prijono9c461142008-07-10 22:41:20 +0000156
157class Error:
Benny Prijonob85ba652008-07-11 00:55:22 +0000158 """Error exception class.
159
160 Member documentation:
161
162 op_name -- name of the operation that generated this error.
163 obj -- the object that generated this error.
164 err_code -- the error code.
165
166 """
Benny Prijono9c461142008-07-10 22:41:20 +0000167 op_name = ""
168 obj = None
169 err_code = -1
170 _err_msg = ""
171
172 def __init__(self, op_name, obj, err_code, err_msg=""):
173 self.op_name = op_name
174 self.obj = obj
175 self.err_code = err_code
176 self._err_msg = err_msg
177
178 def err_msg(self):
179 "Retrieve the description of the error."
180 if self._err_msg != "":
181 return self._err_msg
182 self._err_msg = Lib.strerror(self.err_code)
183 return self._err_msg
184
185 def __str__(self):
186 return "Object: " + str(self.obj) + ", operation=" + self.op_name + \
187 ", error=" + self.err_msg()
188
189#
190# Constants
191#
192
193class TransportType:
Benny Prijonob85ba652008-07-11 00:55:22 +0000194 """SIP transport type constants.
195
196 Member documentation:
197 UNSPECIFIED -- transport type is unknown or unspecified
198 UDP -- UDP transport
199 TCP -- TCP transport
200 TLS -- TLS transport
201 IPV6 -- this is not a transport type but rather a flag
202 to select the IPv6 version of a transport
203 UDP_IPV6 -- IPv6 UDP transport
204 TCP_IPV6 -- IPv6 TCP transport
205 """
Benny Prijono9c461142008-07-10 22:41:20 +0000206 UNSPECIFIED = 0
207 UDP = 1
208 TCP = 2
209 TLS = 3
210 IPV6 = 128
211 UDP_IPV6 = UDP + IPV6
212 TCP_IPV6 = TCP + IPV6
213
214class TransportFlag:
Benny Prijonob85ba652008-07-11 00:55:22 +0000215 """Transport flags to indicate the characteristics of the transport.
216
217 Member documentation:
218
219 RELIABLE -- transport is reliable.
220 SECURE -- transport is secure.
221 DATAGRAM -- transport is datagram based.
222
223 """
Benny Prijono9c461142008-07-10 22:41:20 +0000224 RELIABLE = 1
225 SECURE = 2
226 DATAGRAM = 4
227
228class CallRole:
Benny Prijonob85ba652008-07-11 00:55:22 +0000229 """Call role constants.
230
231 Member documentation:
232
233 CALLER -- role is caller
234 CALLEE -- role is callee
235
236 """
Benny Prijono9c461142008-07-10 22:41:20 +0000237 CALLER = 0
238 CALLEE = 1
239
240class CallState:
Benny Prijonob85ba652008-07-11 00:55:22 +0000241 """Call state constants.
242
243 Member documentation:
244
245 NULL -- call is not initialized.
246 CALLING -- initial INVITE is sent.
247 INCOMING -- initial INVITE is received.
248 EARLY -- provisional response has been sent or received.
249 CONNECTING -- 200/OK response has been sent or received.
250 CONFIRMED -- ACK has been sent or received.
251 DISCONNECTED -- call is disconnected.
252 """
Benny Prijono9c461142008-07-10 22:41:20 +0000253 NULL = 0
254 CALLING = 1
255 INCOMING = 2
256 EARLY = 3
257 CONNECTING = 4
258 CONFIRMED = 5
259 DISCONNECTED = 6
260
261
262class MediaState:
Benny Prijonob85ba652008-07-11 00:55:22 +0000263 """Call media state constants.
264
265 Member documentation:
266
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000267 NULL -- media is not available.
Benny Prijonob85ba652008-07-11 00:55:22 +0000268 ACTIVE -- media is active.
269 LOCAL_HOLD -- media is put on-hold by local party.
270 REMOTE_HOLD -- media is put on-hold by remote party.
271 ERROR -- media error (e.g. ICE negotiation failure).
272 """
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000273 NULL = 0
Benny Prijono9c461142008-07-10 22:41:20 +0000274 ACTIVE = 1
275 LOCAL_HOLD = 2
276 REMOTE_HOLD = 3
277 ERROR = 4
278
279
280class MediaDir:
Benny Prijonob85ba652008-07-11 00:55:22 +0000281 """Media direction constants.
282
283 Member documentation:
284
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000285 NULL -- media is not active
Benny Prijonob85ba652008-07-11 00:55:22 +0000286 ENCODING -- media is active in transmit/encoding direction only.
287 DECODING -- media is active in receive/decoding direction only
288 ENCODING_DECODING -- media is active in both directions.
289 """
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000290 NULL = 0
Benny Prijono9c461142008-07-10 22:41:20 +0000291 ENCODING = 1
292 DECODING = 2
293 ENCODING_DECODING = 3
294
295
296class PresenceActivity:
Benny Prijonob85ba652008-07-11 00:55:22 +0000297 """Presence activities constants.
298
299 Member documentation:
300
301 UNKNOWN -- the person activity is unknown
302 AWAY -- the person is currently away
303 BUSY -- the person is currently engaging in other activity
304 """
Benny Prijono9c461142008-07-10 22:41:20 +0000305 UNKNOWN = 0
306 AWAY = 1
307 BUSY = 2
308
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000309
310class SubscriptionState:
311 """Presence subscription state constants.
312
313 """
314 NULL = 0
315 SENT = 1
316 ACCEPTED = 2
317 PENDING = 3
318 ACTIVE = 4
319 TERMINATED = 5
320 UNKNOWN = 6
321
322
Benny Prijono9c461142008-07-10 22:41:20 +0000323class TURNConnType:
Benny Prijonob85ba652008-07-11 00:55:22 +0000324 """These constants specifies the connection type to TURN server.
325
326 Member documentation:
327 UDP -- use UDP transport.
328 TCP -- use TCP transport.
329 TLS -- use TLS transport.
330 """
Benny Prijono9c461142008-07-10 22:41:20 +0000331 UDP = 17
332 TCP = 6
333 TLS = 255
334
335
336class UAConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000337 """User agent configuration to be specified in Lib.init().
338
339 Member documentation:
340
341 max_calls -- maximum number of calls to be supported.
Benny Prijono288d4bd2008-07-19 15:40:21 +0000342 nameserver -- list of nameserver hostnames or IP addresses. Nameserver
Benny Prijonob85ba652008-07-11 00:55:22 +0000343 must be configured if DNS SRV resolution is desired.
344 stun_domain -- if nameserver is configured, this can be used to query
345 the STUN server with DNS SRV.
346 stun_host -- the hostname or IP address of the STUN server. This will
347 also be used if DNS SRV resolution for stun_domain fails.
348 user_agent -- Optionally specify the user agent name.
349 """
Benny Prijono9c461142008-07-10 22:41:20 +0000350 max_calls = 4
351 nameserver = []
352 stun_domain = ""
353 stun_host = ""
354 user_agent = "pjsip python"
355
356 def _cvt_from_pjsua(self, cfg):
357 self.max_calls = cfg.max_calls
358 self.thread_cnt = cfg.thread_cnt
359 self.nameserver = cfg.nameserver
360 self.stun_domain = cfg.stun_domain
361 self.stun_host = cfg.stun_host
362 self.user_agent = cfg.user_agent
363
364 def _cvt_to_pjsua(self):
365 cfg = _pjsua.config_default()
366 cfg.max_calls = self.max_calls
367 cfg.thread_cnt = 0
368 cfg.nameserver = self.nameserver
369 cfg.stun_domain = self.stun_domain
370 cfg.stun_host = self.stun_host
371 cfg.user_agent = self.user_agent
372 return cfg
373
374
375class LogConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000376 """Logging configuration to be specified in Lib.init().
377
378 Member documentation:
379
380 msg_logging -- specify if SIP messages should be logged. Set to
381 True.
382 level -- specify the input verbosity level.
383 console_level -- specify the output verbosity level.
384 decor -- specify log decoration.
385 filename -- specify the log filename.
386 callback -- specify callback to be called to write the logging
387 messages. Sample function:
388
389 def log_cb(level, str, len):
390 print str,
391
392 """
Benny Prijono9c461142008-07-10 22:41:20 +0000393 msg_logging = True
394 level = 5
395 console_level = 5
396 decor = 0
397 filename = ""
398 callback = None
399
400 def __init__(self, level=-1, filename="", callback=None,
401 console_level=-1):
402 self._cvt_from_pjsua(_pjsua.logging_config_default())
403 if level != -1:
404 self.level = level
405 if filename != "":
406 self.filename = filename
407 if callback != None:
408 self.callback = callback
409 if console_level != -1:
410 self.console_level = console_level
411
412 def _cvt_from_pjsua(self, cfg):
413 self.msg_logging = cfg.msg_logging
414 self.level = cfg.level
415 self.console_level = cfg.console_level
416 self.decor = cfg.decor
417 self.filename = cfg.log_filename
418 self.callback = cfg.cb
419
420 def _cvt_to_pjsua(self):
421 cfg = _pjsua.logging_config_default()
422 cfg.msg_logging = self.msg_logging
423 cfg.level = self.level
424 cfg.console_level = self.console_level
425 cfg.decor = self.decor
426 cfg.log_filename = self.filename
427 cfg.cb = self.callback
428 return cfg
429
430
431class MediaConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000432 """Media configuration to be specified in Lib.init().
433
434 Member documentation:
435
436 clock_rate -- specify the core clock rate of the audio,
437 most notably the conference bridge.
438 snd_clock_rate -- optionally specify different clock rate for
439 the sound device.
440 snd_auto_close_time -- specify the duration in seconds when the
441 sound device should be closed after inactivity
442 period.
443 channel_count -- specify the number of channels to open the sound
444 device and the conference bridge.
445 audio_frame_ptime -- specify the length of audio frames in millisecond.
446 max_media_ports -- specify maximum number of audio ports to be
447 supported by the conference bridge.
448 quality -- specify the audio quality setting (1-10)
449 ptime -- specify the audio packet length of transmitted
450 RTP packet.
451 no_vad -- disable Voice Activity Detector (VAD) or Silence
452 Detector (SD)
453 ilbc_mode -- specify iLBC codec mode (must be 30 for now)
454 tx_drop_pct -- randomly drop transmitted RTP packets (for
455 simulation). Number is in percent.
456 rx_drop_pct -- randomly drop received RTP packets (for
457 simulation). Number is in percent.
458 ec_options -- Echo Canceller option (specify zero).
459 ec_tail_len -- specify Echo Canceller tail length in milliseconds.
460 Value zero will disable the echo canceller.
461 jb_min -- specify the minimum jitter buffer size in
462 milliseconds. Put -1 for default.
463 jb_max -- specify the maximum jitter buffer size in
464 milliseconds. Put -1 for default.
465 enable_ice -- enable Interactive Connectivity Establishment (ICE)
466 enable_turn -- enable TURN relay. TURN server settings must also
467 be configured.
468 turn_server -- specify the domain or hostname or IP address of
469 the TURN server, in "host[:port]" format.
470 turn_conn_type -- specify connection type to the TURN server, from
471 the TURNConnType constant.
472 turn_cred -- specify AuthCred for the TURN credential.
473 """
Benny Prijono9c461142008-07-10 22:41:20 +0000474 clock_rate = 16000
475 snd_clock_rate = 0
476 snd_auto_close_time = 5
477 channel_count = 1
478 audio_frame_ptime = 20
479 max_media_ports = 32
480 quality = 6
481 ptime = 0
482 no_vad = False
483 ilbc_mode = 30
484 tx_drop_pct = 0
485 rx_drop_pct = 0
486 ec_options = 0
487 ec_tail_len = 256
488 jb_min = -1
489 jb_max = -1
490 enable_ice = True
491 enable_turn = False
492 turn_server = ""
493 turn_conn_type = TURNConnType.UDP
494 turn_cred = None
495
496 def __init__(self):
497 default = _pjsua.media_config_default()
498 self._cvt_from_pjsua(default)
499
500 def _cvt_from_pjsua(self, cfg):
501 self.clock_rate = cfg.clock_rate
502 self.snd_clock_rate = cfg.snd_clock_rate
503 self.snd_auto_close_time = cfg.snd_auto_close_time
504 self.channel_count = cfg.channel_count
505 self.audio_frame_ptime = cfg.audio_frame_ptime
506 self.max_media_ports = cfg.max_media_ports
507 self.quality = cfg.quality
508 self.ptime = cfg.ptime
509 self.no_vad = cfg.no_vad
510 self.ilbc_mode = cfg.ilbc_mode
511 self.tx_drop_pct = cfg.tx_drop_pct
512 self.rx_drop_pct = cfg.rx_drop_pct
513 self.ec_options = cfg.ec_options
514 self.ec_tail_len = cfg.ec_tail_len
515 self.jb_min = cfg.jb_min
516 self.jb_max = cfg.jb_max
517 self.enable_ice = cfg.enable_ice
518 self.enable_turn = cfg.enable_turn
519 self.turn_server = cfg.turn_server
520 self.turn_conn_type = cfg.turn_conn_type
521 if cfg.turn_username:
522 self.turn_cred = AuthCred(cfg.turn_realm, cfg.turn_username,
523 cfg.turn_passwd, cfg.turn_passwd_type)
524 else:
525 self.turn_cred = None
526
527 def _cvt_to_pjsua(self):
528 cfg = _pjsua.media_config_default()
529 cfg.clock_rate = self.clock_rate
530 cfg.snd_clock_rate = self.snd_clock_rate
531 cfg.snd_auto_close_time = self.snd_auto_close_time
532 cfg.channel_count = self.channel_count
533 cfg.audio_frame_ptime = self.audio_frame_ptime
534 cfg.max_media_ports = self.max_media_ports
535 cfg.quality = self.quality
536 cfg.ptime = self.ptime
537 cfg.no_vad = self.no_vad
538 cfg.ilbc_mode = self.ilbc_mode
539 cfg.tx_drop_pct = self.tx_drop_pct
540 cfg.rx_drop_pct = self.rx_drop_pct
541 cfg.ec_options = self.ec_options
542 cfg.ec_tail_len = self.ec_tail_len
543 cfg.jb_min = self.jb_min
544 cfg.jb_max = self.jb_max
545 cfg.enable_ice = self.enable_ice
546 cfg.enable_turn = self.enable_turn
547 cfg.turn_server = self.turn_server
548 cfg.turn_conn_type = self.turn_conn_type
549 if self.turn_cred:
550 cfg.turn_realm = self.turn_cred.realm
551 cfg.turn_username = self.turn_cred.username
552 cfg.turn_passwd_type = self.turn_cred.passwd_type
553 cfg.turn_passwd = self.turn_cred.passwd
554 return cfg
555
556
557class TransportConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000558 """SIP transport configuration class.
559
560 Member configuration:
561
562 port -- port number.
563 bound_addr -- optionally specify the address to bind the socket to.
564 Default is empty to bind to INADDR_ANY.
565 public_addr -- optionally override the published address for this
566 transport. If empty, the default behavior is to get
567 the public address from STUN or from the selected
568 local interface. Format is "host:port".
569 """
Benny Prijono9c461142008-07-10 22:41:20 +0000570 port = 0
571 bound_addr = ""
572 public_addr = ""
573
574 def __init__(self, port=5060,
575 bound_addr="", public_addr=""):
576 self.port = port
577 self.bound_addr = bound_addr
578 self.public_addr = public_addr
579
580 def _cvt_to_pjsua(self):
581 cfg = _pjsua.transport_config_default()
582 cfg.port = self.port
583 cfg.bound_addr = self.bound_addr
584 cfg.public_addr = self.public_addr
585 return cfg
586
587
588class TransportInfo:
589 """SIP transport info.
Benny Prijonob85ba652008-07-11 00:55:22 +0000590
591 Member documentation:
592
593 type -- transport type, from TransportType constants.
594 description -- longer description for this transport.
595 is_reliable -- True if transport is reliable.
596 is_secure -- True if transport is secure.
597 is_datagram -- True if transport is datagram based.
598 host -- the IP address of this transport.
599 port -- the port number.
600 ref_cnt -- number of objects referencing this transport.
Benny Prijono9c461142008-07-10 22:41:20 +0000601 """
602 type = ""
603 description = ""
604 is_reliable = False
605 is_secure = False
606 is_datagram = False
607 host = ""
608 port = 0
609 ref_cnt = 0
610
611 def __init__(self, ti):
612 self.type = ti.type_name
613 self.description = ti.info
614 self.is_reliable = (ti.flag & TransportFlag.RELIABLE)
615 self.is_secure = (ti.flag & TransportFlag.SECURE)
616 self.is_datagram = (ti.flag & TransportFlag.DATAGRAM)
617 self.host = ti.addr
618 self.port = ti.port
619 self.ref_cnt = ti.usage_count
620
621
622class Transport:
623 "SIP transport class."
624 _id = -1
625 _lib = None
626 _obj_name = ""
627
628 def __init__(self, lib, id):
Benny Prijono55040452008-07-21 18:20:57 +0000629 self._lib = weakref.proxy(lib)
Benny Prijono9c461142008-07-10 22:41:20 +0000630 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +0000631 self._obj_name = "{Transport " + self.info().description + "}"
632 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +0000633
Benny Prijono55040452008-07-21 18:20:57 +0000634 def __del__(self):
635 _Trace((self, 'destroyed'))
636
Benny Prijono9c461142008-07-10 22:41:20 +0000637 def __str__(self):
638 return self._obj_name
639
640 def info(self):
641 """Get TransportInfo.
642 """
Benny Prijono55040452008-07-21 18:20:57 +0000643 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000644 ti = _pjsua.transport_get_info(self._id)
645 if not ti:
646 self._lib._err_check("info()", self, -1, "Invalid transport")
647 return TransportInfo(ti)
648
649 def enable(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000650 """Enable this transport."""
Benny Prijono55040452008-07-21 18:20:57 +0000651 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000652 err = _pjsua.transport_set_enable(self._id, True)
653 self._lib._err_check("enable()", self, err)
654
655 def disable(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000656 """Disable this transport."""
Benny Prijono55040452008-07-21 18:20:57 +0000657 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000658 err = _pjsua.transport_set_enable(self._id, 0)
659 self._lib._err_check("disable()", self, err)
660
661 def close(self, force=False):
Benny Prijonob85ba652008-07-11 00:55:22 +0000662 """Close and destroy this transport.
663
664 Keyword argument:
665 force -- force deletion of this transport (not recommended).
666 """
Benny Prijono55040452008-07-21 18:20:57 +0000667 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000668 err = _pjsua.transport_close(self._id, force)
669 self._lib._err_check("close()", self, err)
670
671
672class SIPUri:
Benny Prijonob85ba652008-07-11 00:55:22 +0000673 """Helper class to parse the most important components of SIP URI.
674
675 Member documentation:
676
677 scheme -- URI scheme ("sip" or "sips")
678 user -- user part of the URI (may be empty)
679 host -- host name part
680 port -- optional port number (zero if port is not specified).
681 transport -- transport parameter, or empty if transport is not
682 specified.
683
684 """
Benny Prijono9c461142008-07-10 22:41:20 +0000685 scheme = ""
686 user = ""
687 host = ""
688 port = 0
689 transport = ""
690
Benny Prijonob85ba652008-07-11 00:55:22 +0000691 def __init__(self, uri=None):
692 if uri:
693 self.decode(uri)
Benny Prijono9c461142008-07-10 22:41:20 +0000694
695 def decode(self, uri):
Benny Prijonob85ba652008-07-11 00:55:22 +0000696 """Parse SIP URL.
697
698 Keyword argument:
699 uri -- the URI string.
700
701 """
Benny Prijono9c461142008-07-10 22:41:20 +0000702 self.scheme, self.user, self.host, self.port, self.transport = \
703 _pjsua.parse_simple_uri(uri)
704
705 def encode(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000706 """Encode this object into SIP URI string.
707
708 Return:
709 URI string.
710
711 """
Benny Prijono9c461142008-07-10 22:41:20 +0000712 output = self.scheme + ":"
713 if self.user and len(self.user):
714 output = output + self.user + "@"
715 output = output + self.host
716 if self.port:
717 output = output + ":" + output(self.port)
718 if self.transport:
719 output = output + ";transport=" + self.transport
720 return output
721
Benny Prijonob85ba652008-07-11 00:55:22 +0000722
Benny Prijono9c461142008-07-10 22:41:20 +0000723class AuthCred:
Benny Prijonob85ba652008-07-11 00:55:22 +0000724 """Authentication credential for SIP or TURN account.
725
726 Member documentation:
727
728 scheme -- authentication scheme (default is "Digest")
729 realm -- realm
730 username -- username
731 passwd_type -- password encoding (zero for plain-text)
732 passwd -- the password
733 """
Benny Prijono9c461142008-07-10 22:41:20 +0000734 scheme = "Digest"
735 realm = "*"
736 username = ""
737 passwd_type = 0
738 passwd = ""
739
740 def __init__(self, realm, username, passwd, scheme="Digest", passwd_type=0):
741 self.scheme = scheme
742 self.realm = realm
743 self.username = username
744 self.passwd_type = passwd_type
745 self.passwd = passwd
746
747
748class AccountConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000749 """ This describes account configuration to create an account.
750
751 Member documentation:
752
753 priority -- account priority for matching incoming
754 messages.
755 id -- SIP URI of this account. This setting is
756 mandatory.
757 force_contact -- force to use this URI as Contact URI. Setting
758 this value is generally not recommended.
759 reg_uri -- specify the registrar URI. Mandatory if
760 registration is required.
761 reg_timeout -- specify the SIP registration refresh interval
762 in seconds.
763 require_100rel -- specify if reliable provisional response is
764 to be enforced (with Require header).
765 publish_enabled -- specify if PUBLISH should be used. When
766 enabled, the PUBLISH will be sent to the
767 registrar.
768 pidf_tuple_id -- optionally specify the tuple ID in outgoing
769 PIDF document.
770 proxy -- list of proxy URI.
771 auth_cred -- list of AuthCred containing credentials to
772 authenticate against the registrars and
773 the proxies.
774 auth_initial_send -- specify if empty Authorization header should be
775 sent. May be needed for IMS.
776 auth_initial_algorithm -- when auth_initial_send is enabled, optionally
777 specify the authentication algorithm to use.
778 Valid values are "md5", "akav1-md5", or
779 "akav2-md5".
780 transport_id -- optionally specify the transport ID to be used
781 by this account. Shouldn't be needed unless
782 for specific requirements (e.g. in multi-homed
783 scenario).
784 allow_contact_rewrite -- specify whether the account should learn its
785 Contact address from REGISTER response and
786 update the registration accordingly. Default is
787 True.
788 ka_interval -- specify the interval to send NAT keep-alive
789 packet.
790 ka_data -- specify the NAT keep-alive packet contents.
791 use_srtp -- specify the SRTP usage policy. Valid values
792 are: 0=disable, 1=optional, 2=mandatory.
793 Default is 0.
794 srtp_secure_signaling -- specify the signaling security level required
795 by SRTP. Valid values are: 0=no secure
796 transport is required, 1=hop-by-hop secure
797 transport such as TLS is required, 2=end-to-
798 end secure transport is required (i.e. "sips").
Benny Prijono9c461142008-07-10 22:41:20 +0000799 """
800 priority = 0
801 id = ""
802 force_contact = ""
803 reg_uri = ""
804 reg_timeout = 0
805 require_100rel = False
806 publish_enabled = False
807 pidf_tuple_id = ""
808 proxy = []
809 auth_cred = []
810 auth_initial_send = False
811 auth_initial_algorithm = ""
812 transport_id = -1
813 allow_contact_rewrite = True
814 ka_interval = 15
815 ka_data = "\r\n"
816 use_srtp = 0
817 srtp_secure_signaling = 1
818
819 def __init__(self, domain="", username="", password="",
820 display="", registrar="", proxy=""):
821 """
822 Construct account config. If domain argument is specified,
823 a typical configuration will be built.
824
825 Keyword arguments:
826 domain -- domain name of the server.
827 username -- user name.
828 password -- plain-text password.
829 display -- optional display name for the user name.
830 registrar -- the registrar URI. If domain name is specified
831 and this argument is empty, the registrar URI
832 will be constructed from the domain name.
833 proxy -- the proxy URI. If domain name is specified
834 and this argument is empty, the proxy URI
835 will be constructed from the domain name.
836
837 """
838 default = _pjsua.acc_config_default()
839 self._cvt_from_pjsua(default)
840 if domain!="":
841 self.build_config(domain, username, password,
842 display, registrar, proxy)
843
844 def build_config(self, domain, username, password, display="",
845 registrar="", proxy=""):
846 """
847 Construct account config. If domain argument is specified,
848 a typical configuration will be built.
849
850 Keyword arguments:
851 domain -- domain name of the server.
852 username -- user name.
853 password -- plain-text password.
854 display -- optional display name for the user name.
855 registrar -- the registrar URI. If domain name is specified
856 and this argument is empty, the registrar URI
857 will be constructed from the domain name.
858 proxy -- the proxy URI. If domain name is specified
859 and this argument is empty, the proxy URI
860 will be constructed from the domain name.
861
862 """
863 if display != "":
864 display = display + " "
865 userpart = username
866 if userpart != "":
867 userpart = userpart + "@"
868 self.id = display + "<sip:" + userpart + domain + ">"
869 self.reg_uri = registrar
870 if self.reg_uri == "":
871 self.reg_uri = "sip:" + domain
872 if proxy == "":
873 proxy = "sip:" + domain + ";lr"
874 if proxy.find(";lr") == -1:
875 proxy = proxy + ";lr"
876 self.proxy.append(proxy)
877 if username != "":
878 self.auth_cred.append(AuthCred("*", username, password))
879
880 def _cvt_from_pjsua(self, cfg):
881 self.priority = cfg.priority
882 self.id = cfg.id
883 self.force_contact = cfg.force_contact
884 self.reg_uri = cfg.reg_uri
885 self.reg_timeout = cfg.reg_timeout
886 self.require_100rel = cfg.require_100rel
887 self.publish_enabled = cfg.publish_enabled
888 self.pidf_tuple_id = cfg.pidf_tuple_id
889 self.proxy = cfg.proxy
890 for cred in cfg.cred_info:
891 self.auth_cred.append(AuthCred(cred.realm, cred.username,
892 cred.data, cred.scheme,
893 cred.data_type))
894 self.auth_initial_send = cfg.auth_initial_send
895 self.auth_initial_algorithm = cfg.auth_initial_algorithm
896 self.transport_id = cfg.transport_id
897 self.allow_contact_rewrite = cfg.allow_contact_rewrite
898 self.ka_interval = cfg.ka_interval
899 self.ka_data = cfg.ka_data
900 self.use_srtp = cfg.use_srtp
901 self.srtp_secure_signaling = cfg.srtp_secure_signaling
902
903 def _cvt_to_pjsua(self):
904 cfg = _pjsua.acc_config_default()
905 cfg.priority = self.priority
906 cfg.id = self.id
907 cfg.force_contact = self.force_contact
908 cfg.reg_uri = self.reg_uri
909 cfg.reg_timeout = self.reg_timeout
910 cfg.require_100rel = self.require_100rel
911 cfg.publish_enabled = self.publish_enabled
912 cfg.pidf_tuple_id = self.pidf_tuple_id
913 cfg.proxy = self.proxy
914 for cred in self.auth_cred:
915 c = _pjsua.Pjsip_Cred_Info()
916 c.realm = cred.realm
917 c.scheme = cred.scheme
918 c.username = cred.username
919 c.data_type = cred.passwd_type
920 c.data = cred.passwd
921 cfg.cred_info.append(c)
922 cfg.auth_initial_send = self.auth_initial_send
923 cfg.auth_initial_algorithm = self.auth_initial_algorithm
924 cfg.transport_id = self.transport_id
925 cfg.allow_contact_rewrite = self.allow_contact_rewrite
926 cfg.ka_interval = self.ka_interval
927 cfg.ka_data = self.ka_data
928 cfg.use_srtp = self.use_srtp
929 cfg.srtp_secure_signaling = self.srtp_secure_signaling
930 return cfg
931
932
933# Account information
934class AccountInfo:
935 """This describes Account info. Application retrives account info
936 with Account.info().
937
Benny Prijonob85ba652008-07-11 00:55:22 +0000938 Member documentation:
939
940 is_default -- True if this is the default account.
941 uri -- the account URI.
942 reg_active -- True if registration is active for this account.
943 reg_expires -- contains the current registration expiration value,
944 in seconds.
945 reg_status -- the registration status. If the value is less than
946 700, it specifies SIP status code. Value greater than
947 this specifies the error code.
948 reg_reason -- contains the registration status text (e.g. the
949 error message).
950 online_status -- the account's presence online status, True if it's
951 publishing itself as online.
952 online_text -- the account's presence status text.
953
Benny Prijono9c461142008-07-10 22:41:20 +0000954 """
955 is_default = False
956 uri = ""
957 reg_active = False
958 reg_expires = -1
959 reg_status = 0
960 reg_reason = ""
961 online_status = False
962 online_text = ""
963
964 def __init__(self, ai):
965 self.is_default = ai.is_default
966 self.uri = ai.acc_uri
967 self.reg_active = ai.has_registration
968 self.reg_expires = ai.expires
969 self.reg_status = ai.status
970 self.reg_reason = ai.status_text
971 self.online_status = ai.online_status
972 self.online_text = ai.online_status_text
973
974# Account callback
975class AccountCallback:
976 """Class to receive notifications on account's events.
977
978 Derive a class from this class and register it to the Account object
979 using Account.set_callback() to start receiving events from the Account
980 object.
Benny Prijonob85ba652008-07-11 00:55:22 +0000981
982 Member documentation:
983
984 account -- the Account object.
985
Benny Prijono9c461142008-07-10 22:41:20 +0000986 """
987 account = None
988
Benny Prijono55040452008-07-21 18:20:57 +0000989 def __init__(self, account=None):
990 self._set_account(account)
991
992 def __del__(self):
993 pass
994
995 def _set_account(self, account):
996 if account:
997 self.account = weakref.proxy(account)
998 else:
999 self.account = None
Benny Prijono9c461142008-07-10 22:41:20 +00001000
1001 def on_reg_state(self):
1002 """Notification that the registration status has changed.
1003 """
1004 pass
1005
1006 def on_incoming_call(self, call):
1007 """Notification about incoming call.
1008
1009 Unless this callback is implemented, the default behavior is to
1010 reject the call with default status code.
1011
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001012 Keyword arguments:
1013 call -- the new incoming call
Benny Prijono9c461142008-07-10 22:41:20 +00001014 """
1015 call.hangup()
1016
Benny Prijono55040452008-07-21 18:20:57 +00001017 def on_incoming_subscribe(self, buddy, from_uri, contact_uri, pres_obj):
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001018 """Notification when incoming SUBSCRIBE request is received.
1019
1020 Application may use this callback to authorize the incoming
1021 subscribe request (e.g. ask user permission if the request
1022 should be granted)
1023
1024 Keyword arguments:
1025 buddy -- The buddy object, if buddy is found. Otherwise
1026 the value is None.
1027 from_uri -- The URI string of the sender.
1028 pres_obj -- Opaque presence subscription object, which is
1029 needed by Account.pres_notify()
1030
1031 Return:
1032 Tuple (code, reason), where:
1033 code: The status code. If code is >= 300, the
1034 request is rejected. If code is 200, the
1035 request is accepted and NOTIFY will be sent
1036 automatically. If code is 202, application
1037 must accept or reject the request later with
1038 Account.press_notify().
1039 reason: Optional reason phrase, or None to use the
1040 default reasoh phrase for the status code.
1041 """
1042 return (200, None)
1043
Benny Prijono9c461142008-07-10 22:41:20 +00001044 def on_pager(self, from_uri, contact, mime_type, body):
1045 """
1046 Notification that incoming instant message is received on
1047 this account.
1048
1049 Keyword arguments:
1050 from_uri -- sender's URI
1051 contact -- sender's Contact URI
1052 mime_type -- MIME type of the instant message body
1053 body -- the instant message body
1054
1055 """
1056 pass
1057
1058 def on_pager_status(self, to_uri, body, im_id, code, reason):
1059 """
1060 Notification about the delivery status of previously sent
1061 instant message.
1062
1063 Keyword arguments:
1064 to_uri -- the destination URI of the message
1065 body -- the message body
1066 im_id -- message ID
1067 code -- SIP status code
1068 reason -- SIP reason phrase
1069
1070 """
1071 pass
1072
1073 def on_typing(self, from_uri, contact, is_typing):
1074 """
1075 Notification that remote is typing or stop typing.
1076
1077 Keyword arguments:
1078 buddy -- Buddy object for the sender, if found. Otherwise
1079 this will be None
1080 from_uri -- sender's URI of the indication
1081 contact -- sender's contact URI
1082 is_typing -- boolean to indicate whether remote is currently
1083 typing an instant message.
1084
1085 """
1086 pass
1087
1088
1089
1090class Account:
1091 """This describes SIP account class.
1092
1093 PJSUA accounts provide identity (or identities) of the user who is
1094 currently using the application. In SIP terms, the identity is used
1095 as the From header in outgoing requests.
1096
1097 Account may or may not have client registration associated with it.
1098 An account is also associated with route set and some authentication
1099 credentials, which are used when sending SIP request messages using
1100 the account. An account also has presence's online status, which
1101 will be reported to remote peer when they subscribe to the account's
1102 presence, or which is published to a presence server if presence
1103 publication is enabled for the account.
1104
1105 Account is created with Lib.create_account(). At least one account
1106 MUST be created. If no user association is required, application can
1107 create a userless account by calling Lib.create_account_for_transport().
1108 A userless account identifies local endpoint instead of a particular
1109 user, and it correspond with a particular transport instance.
1110
1111 Also one account must be set as the default account, which is used as
1112 the account to use when PJSUA fails to match a request with any other
1113 accounts.
1114
1115 """
1116 _id = -1
1117 _lib = None
1118 _cb = AccountCallback(None)
1119 _obj_name = ""
1120
Benny Prijono55040452008-07-21 18:20:57 +00001121 def __init__(self, lib, id, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001122 """Construct this class. This is normally called by Lib class and
1123 not by application.
1124
1125 Keyword arguments:
1126 lib -- the Lib instance.
1127 id -- the pjsua account ID.
Benny Prijono55040452008-07-21 18:20:57 +00001128 cb -- AccountCallback instance to receive events from this Account.
1129 If callback is not specified here, it must be set later
1130 using set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001131 """
Benny Prijono9c461142008-07-10 22:41:20 +00001132 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +00001133 self._lib = weakref.ref(lib)
1134 self._obj_name = "{Account " + self.info().uri + "}"
1135 self.set_callback(cb)
1136 _pjsua.acc_set_user_data(self._id, self)
1137 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001138
1139 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001140 if self._id != -1:
1141 _pjsua.acc_set_user_data(self._id, 0)
1142 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001143
1144 def __str__(self):
1145 return self._obj_name
1146
1147 def info(self):
1148 """Retrieve AccountInfo for this account.
1149 """
Benny Prijono55040452008-07-21 18:20:57 +00001150 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001151 ai = _pjsua.acc_get_info(self._id)
1152 if ai==None:
Benny Prijono55040452008-07-21 18:20:57 +00001153 self._lib()._err_check("info()", self, -1, "Invalid account")
Benny Prijono9c461142008-07-10 22:41:20 +00001154 return AccountInfo(ai)
1155
1156 def is_valid(self):
1157 """
1158 Check if this account is still valid.
1159
1160 """
Benny Prijono55040452008-07-21 18:20:57 +00001161 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001162 return _pjsua.acc_is_valid(self._id)
1163
1164 def set_callback(self, cb):
1165 """Register callback to receive notifications from this object.
1166
1167 Keyword argument:
1168 cb -- AccountCallback instance.
1169
1170 """
1171 if cb:
1172 self._cb = cb
1173 else:
1174 self._cb = AccountCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001175 self._cb._set_account(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001176
1177 def set_default(self):
1178 """ Set this account as default account to send outgoing requests
1179 and as the account to receive incoming requests when more exact
1180 matching criteria fails.
1181 """
Benny Prijono55040452008-07-21 18:20:57 +00001182 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001183 err = _pjsua.acc_set_default(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001184 self._lib()._err_check("set_default()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001185
1186 def is_default(self):
1187 """ Check if this account is the default account.
1188
1189 """
Benny Prijono55040452008-07-21 18:20:57 +00001190 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001191 def_id = _pjsua.acc_get_default()
1192 return self.is_valid() and def_id==self._id
1193
1194 def delete(self):
1195 """ Delete this account.
1196
1197 """
Benny Prijono55040452008-07-21 18:20:57 +00001198 lck = self._lib().auto_lock()
1199 err = _pjsua.acc_set_user_data(self._id, 0)
1200 self._lib()._err_check("delete()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001201 err = _pjsua.acc_del(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001202 self._lib()._err_check("delete()", self, err)
1203 self._id = -1
Benny Prijono9c461142008-07-10 22:41:20 +00001204
1205 def set_basic_status(self, is_online):
1206 """ Set basic presence status of this account.
1207
1208 Keyword argument:
1209 is_online -- boolean to indicate basic presence availability.
1210
1211 """
Benny Prijono55040452008-07-21 18:20:57 +00001212 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001213 err = _pjsua.acc_set_online_status(self._id, is_online)
Benny Prijono55040452008-07-21 18:20:57 +00001214 self._lib()._err_check("set_basic_status()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001215
1216 def set_presence_status(self, is_online,
1217 activity=PresenceActivity.UNKNOWN,
1218 pres_text="", rpid_id=""):
1219 """ Set presence status of this account.
1220
1221 Keyword arguments:
1222 is_online -- boolean to indicate basic presence availability
1223 activity -- value from PresenceActivity
1224 pres_text -- optional string to convey additional information about
1225 the activity (such as "On the phone")
1226 rpid_id -- optional string to be placed as RPID ID.
1227
1228 """
Benny Prijono55040452008-07-21 18:20:57 +00001229 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001230 err = _pjsua.acc_set_online_status2(self._id, is_online, activity,
1231 pres_text, rpid_id)
Benny Prijono55040452008-07-21 18:20:57 +00001232 self._lib()._err_check("set_presence_status()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001233
1234 def set_registration(self, renew):
1235 """Manually renew registration or unregister from the server.
1236
1237 Keyword argument:
1238 renew -- boolean to indicate whether registration is renewed.
1239 Setting this value for False will trigger unregistration.
1240
1241 """
Benny Prijono55040452008-07-21 18:20:57 +00001242 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001243 err = _pjsua.acc_set_registration(self._id, renew)
Benny Prijono55040452008-07-21 18:20:57 +00001244 self._lib()._err_check("set_registration()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001245
1246 def set_transport(self, transport):
1247 """Set this account to only use the specified transport to send
1248 outgoing requests.
1249
1250 Keyword argument:
1251 transport -- Transport object.
1252
1253 """
Benny Prijono55040452008-07-21 18:20:57 +00001254 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001255 err = _pjsua.acc_set_transport(self._id, transport._id)
Benny Prijono55040452008-07-21 18:20:57 +00001256 self._lib()._err_check("set_transport()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001257
Benny Prijono55040452008-07-21 18:20:57 +00001258 def make_call(self, dst_uri, cb=None, hdr_list=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001259 """Make outgoing call to the specified URI.
1260
1261 Keyword arguments:
1262 dst_uri -- Destination SIP URI.
Benny Prijono55040452008-07-21 18:20:57 +00001263 cb -- CallCallback instance to be installed to the newly
1264 created Call object. If this CallCallback is not
1265 specified (i.e. None is given), it must be installed
1266 later using call.set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001267 hdr_list -- Optional list of headers to be sent with outgoing
1268 INVITE
1269
Benny Prijono55040452008-07-21 18:20:57 +00001270 Return:
1271 Call instance.
Benny Prijono9c461142008-07-10 22:41:20 +00001272 """
Benny Prijono55040452008-07-21 18:20:57 +00001273 lck = self._lib().auto_lock()
1274 call = Call(self._lib(), -1, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00001275 err, cid = _pjsua.call_make_call(self._id, dst_uri, 0,
Benny Prijono55040452008-07-21 18:20:57 +00001276 call, Lib._create_msg_data(hdr_list))
1277 self._lib()._err_check("make_call()", self, err)
1278 call.attach_to_id(cid)
1279 return call
Benny Prijono9c461142008-07-10 22:41:20 +00001280
Benny Prijono55040452008-07-21 18:20:57 +00001281 def add_buddy(self, uri, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001282 """Add new buddy.
1283
1284 Keyword argument:
Benny Prijono55040452008-07-21 18:20:57 +00001285 uri -- SIP URI of the buddy
1286 cb -- BuddyCallback instance to be installed to the newly
1287 created Buddy object. If this callback is not specified
1288 (i.e. None is given), it must be installed later using
1289 buddy.set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001290
1291 Return:
1292 Buddy object
1293 """
Benny Prijono55040452008-07-21 18:20:57 +00001294 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001295 buddy_cfg = _pjsua.buddy_config_default()
1296 buddy_cfg.uri = uri
1297 buddy_cfg.subscribe = False
1298 err, buddy_id = _pjsua.buddy_add(buddy_cfg)
Benny Prijono55040452008-07-21 18:20:57 +00001299 self._lib()._err_check("add_buddy()", self, err)
1300 buddy = Buddy(self._lib(), buddy_id, self, cb)
1301 return buddy
Benny Prijono9c461142008-07-10 22:41:20 +00001302
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001303 def pres_notify(self, pres_obj, state, reason="", hdr_list=None):
1304 """Send NOTIFY to inform account presence status or to terminate
1305 server side presence subscription.
1306
1307 Keyword arguments:
1308 pres_obj -- The subscription object from on_incoming_subscribe()
1309 callback
1310 state -- Subscription state, from SubscriptionState
1311 reason -- Optional reason phrase.
1312 hdr_list -- Optional header list.
1313 """
Benny Prijono55040452008-07-21 18:20:57 +00001314 lck = self._lib().auto_lock()
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001315 _pjsua.acc_pres_notify(self._id, pres_obj, state, reason,
1316 Lib._create_msg_data(hdr_list))
Benny Prijono9c461142008-07-10 22:41:20 +00001317
1318class CallCallback:
1319 """Class to receive event notification from Call objects.
1320
1321 Use Call.set_callback() method to install instance of this callback
1322 class to receive event notifications from the call object.
Benny Prijonob85ba652008-07-11 00:55:22 +00001323
1324 Member documentation:
1325
1326 call -- the Call object.
1327
Benny Prijono9c461142008-07-10 22:41:20 +00001328 """
1329 call = None
1330
Benny Prijono55040452008-07-21 18:20:57 +00001331 def __init__(self, call=None):
1332 self._set_call(call)
1333
1334 def __del__(self):
1335 pass
1336
1337 def _set_call(self, call):
1338 if call:
1339 self.call = weakref.proxy(call)
1340 else:
1341 self.call = None
Benny Prijono9c461142008-07-10 22:41:20 +00001342
1343 def on_state(self):
1344 """Notification that the call's state has changed.
1345
1346 """
1347 pass
1348
1349 def on_media_state(self):
1350 """Notification that the call's media state has changed.
1351
1352 """
1353 pass
1354
1355 def on_dtmf_digit(self, digits):
1356 """Notification on incoming DTMF digits.
1357
1358 Keyword argument:
1359 digits -- string containing the received digits.
1360
1361 """
1362 pass
1363
1364 def on_transfer_request(self, dst, code):
1365 """Notification that call is being transfered by remote party.
1366
1367 Application can decide to accept/reject transfer request by returning
1368 code greater than or equal to 500. The default behavior is to accept
1369 the transfer by returning 202.
1370
1371 Keyword arguments:
1372 dst -- string containing the destination URI
1373 code -- the suggested status code to return to accept the request.
1374
1375 Return:
1376 the callback should return 202 to accept the request, or 300-699 to
1377 reject the request.
1378
1379 """
1380 return code
1381
1382 def on_transfer_status(self, code, reason, final, cont):
1383 """
1384 Notification about the status of previous call transfer request.
1385
1386 Keyword arguments:
1387 code -- SIP status code to indicate completion status.
1388 text -- SIP status reason phrase.
1389 final -- if True then this is a final status and no further
1390 notifications will be sent for this call transfer
1391 status.
1392 cont -- suggested return value.
1393
1394 Return:
1395 If the callback returns false then no further notification will
1396 be sent for the transfer request for this call.
1397
1398 """
1399 return cont
1400
1401 def on_replace_request(self, code, reason):
1402 """Notification when incoming INVITE with Replaces header is received.
1403
1404 Application may reject the request by returning value greather than
1405 or equal to 500. The default behavior is to accept the request.
1406
1407 Keyword arguments:
1408 code -- default status code to return
1409 reason -- default reason phrase to return
1410
1411 Return:
1412 The callback should return (code, reason) tuple.
1413
1414 """
1415 return code, reason
1416
1417 def on_replaced(self, new_call):
1418 """
1419 Notification that this call will be replaced with new_call.
1420 After this callback is called, this call will be disconnected.
1421
1422 Keyword arguments:
1423 new_call -- the new call that will replace this call.
1424 """
1425 pass
1426
1427 def on_pager(self, mime_type, body):
1428 """
1429 Notification that incoming instant message is received on
1430 this call.
1431
1432 Keyword arguments:
1433 mime_type -- MIME type of the instant message body.
1434 body -- the instant message body.
1435
1436 """
1437 pass
1438
1439 def on_pager_status(self, body, im_id, code, reason):
1440 """
1441 Notification about the delivery status of previously sent
1442 instant message.
1443
1444 Keyword arguments:
1445 body -- message body
1446 im_id -- message ID
1447 code -- SIP status code
1448 reason -- SIP reason phrase
1449
1450 """
1451 pass
1452
1453 def on_typing(self, is_typing):
1454 """
1455 Notification that remote is typing or stop typing.
1456
1457 Keyword arguments:
1458 is_typing -- boolean to indicate whether remote is currently
1459 typing an instant message.
1460
1461 """
1462 pass
1463
1464
1465class CallInfo:
1466 """This structure contains various information about Call.
1467
1468 Application may retrieve this information with Call.info().
Benny Prijonob85ba652008-07-11 00:55:22 +00001469
1470 Member documentation:
1471
1472 role -- CallRole
1473 account -- Account object.
1474 uri -- SIP URI of local account.
1475 contact -- local Contact URI.
1476 remote_uri -- remote SIP URI.
1477 remote_contact -- remote Contact URI
1478 sip_call_id -- call's Call-ID identification
1479 state -- CallState
1480 state_text -- state text.
1481 last_code -- last SIP status code
1482 last_reason -- text phrase for last_code
1483 media_state -- MediaState
1484 media_dir -- MediaDir
1485 conf_slot -- conference slot number for this call.
1486 call_time -- call's connected duration in seconds.
1487 total_time -- total call duration in seconds.
Benny Prijono9c461142008-07-10 22:41:20 +00001488 """
1489 role = CallRole.CALLER
1490 account = None
1491 uri = ""
1492 contact = ""
1493 remote_uri = ""
1494 remote_contact = ""
1495 sip_call_id = ""
1496 state = CallState.NULL
1497 state_text = ""
1498 last_code = 0
1499 last_reason = ""
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001500 media_state = MediaState.NULL
1501 media_dir = MediaDir.NULL
Benny Prijono9c461142008-07-10 22:41:20 +00001502 conf_slot = -1
1503 call_time = 0
1504 total_time = 0
1505
1506 def __init__(self, lib=None, ci=None):
1507 if lib and ci:
1508 self._cvt_from_pjsua(lib, ci)
1509
1510 def _cvt_from_pjsua(self, lib, ci):
1511 self.role = ci.role
1512 self.account = lib._lookup_account(ci.acc_id)
1513 self.uri = ci.local_info
1514 self.contact = ci.local_contact
1515 self.remote_uri = ci.remote_info
1516 self.remote_contact = ci.remote_contact
1517 self.sip_call_id = ci.call_id
1518 self.state = ci.state
1519 self.state_text = ci.state_text
1520 self.last_code = ci.last_status
1521 self.last_reason = ci.last_status_text
1522 self.media_state = ci.media_status
1523 self.media_dir = ci.media_dir
1524 self.conf_slot = ci.conf_slot
Benny Prijono55040452008-07-21 18:20:57 +00001525 self.call_time = ci.connect_duration / 1000
1526 self.total_time = ci.total_duration / 1000
Benny Prijono9c461142008-07-10 22:41:20 +00001527
1528
1529class Call:
1530 """This class represents SIP call.
1531
1532 Application initiates outgoing call with Account.make_call(), and
1533 incoming calls are reported in AccountCallback.on_incoming_call().
1534 """
1535 _id = -1
1536 _cb = None
1537 _lib = None
1538 _obj_name = ""
1539
Benny Prijono55040452008-07-21 18:20:57 +00001540 def __init__(self, lib, call_id, cb=None):
1541 self._lib = weakref.ref(lib)
1542 self.set_callback(cb)
1543 self.attach_to_id(call_id)
1544 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001545
1546 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001547 if self._id != -1:
1548 _pjsua.call_set_user_data(self._id, 0)
1549 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001550
1551 def __str__(self):
1552 return self._obj_name
1553
Benny Prijono55040452008-07-21 18:20:57 +00001554 def attach_to_id(self, call_id):
1555 lck = self._lib().auto_lock()
1556 if self._id != -1:
1557 _pjsua.call_set_user_data(self._id, 0)
1558 self._id = call_id
1559 if self._id != -1:
1560 _pjsua.call_set_user_data(self._id, self)
1561 self._obj_name = "{Call " + self.info().remote_uri + "}"
1562 else:
1563 self._obj_name = "{Call object}"
1564
Benny Prijono9c461142008-07-10 22:41:20 +00001565 def set_callback(self, cb):
1566 """
1567 Set callback object to retrieve event notifications from this call.
1568
1569 Keyword arguments:
1570 cb -- CallCallback instance.
1571 """
1572 if cb:
1573 self._cb = cb
1574 else:
1575 self._cb = CallCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001576 self._cb._set_call(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001577
1578 def info(self):
1579 """
1580 Get the CallInfo.
1581 """
Benny Prijono55040452008-07-21 18:20:57 +00001582 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001583 ci = _pjsua.call_get_info(self._id)
1584 if not ci:
Benny Prijono55040452008-07-21 18:20:57 +00001585 self._lib()._err_check("info", self, -1, "Invalid call")
1586 call_info = CallInfo(self._lib(), ci)
1587 return call_info
Benny Prijono9c461142008-07-10 22:41:20 +00001588
1589 def is_valid(self):
1590 """
1591 Check if this call is still valid.
1592 """
Benny Prijono55040452008-07-21 18:20:57 +00001593 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001594 return _pjsua.call_is_active(self._id)
1595
1596 def dump_status(self, with_media=True, indent="", max_len=1024):
1597 """
1598 Dump the call status.
1599 """
Benny Prijono55040452008-07-21 18:20:57 +00001600 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001601 return _pjsua.call_dump(self._id, with_media, max_len, indent)
1602
1603 def answer(self, code=200, reason="", hdr_list=None):
1604 """
1605 Send provisional or final response to incoming call.
1606
1607 Keyword arguments:
1608 code -- SIP status code.
1609 reason -- Reason phrase. Put empty to send default reason
1610 phrase for the status code.
1611 hdr_list -- Optional list of headers to be sent with the
1612 INVITE response.
1613
1614 """
Benny Prijono55040452008-07-21 18:20:57 +00001615 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001616 err = _pjsua.call_answer(self._id, code, reason,
1617 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001618 self._lib()._err_check("answer()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001619
1620 def hangup(self, code=603, reason="", hdr_list=None):
1621 """
1622 Terminate the call.
1623
1624 Keyword arguments:
1625 code -- SIP status code.
1626 reason -- Reason phrase. Put empty to send default reason
1627 phrase for the status code.
1628 hdr_list -- Optional list of headers to be sent with the
1629 message.
1630
1631 """
Benny Prijono55040452008-07-21 18:20:57 +00001632 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001633 err = _pjsua.call_hangup(self._id, code, reason,
1634 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001635 self._lib()._err_check("hangup()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001636
1637 def hold(self, hdr_list=None):
1638 """
1639 Put the call on hold.
1640
1641 Keyword arguments:
1642 hdr_list -- Optional list of headers to be sent with the
1643 message.
1644 """
Benny Prijono55040452008-07-21 18:20:57 +00001645 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001646 err = _pjsua.call_set_hold(self._id, Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001647 self._lib()._err_check("hold()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001648
1649 def unhold(self, hdr_list=None):
1650 """
1651 Release the call from hold.
1652
1653 Keyword arguments:
1654 hdr_list -- Optional list of headers to be sent with the
1655 message.
1656
1657 """
Benny Prijono55040452008-07-21 18:20:57 +00001658 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001659 err = _pjsua.call_reinvite(self._id, True,
1660 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001661 self._lib()._err_check("unhold()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001662
1663 def reinvite(self, hdr_list=None):
1664 """
1665 Send re-INVITE and optionally offer new codecs to use.
1666
1667 Keyword arguments:
1668 hdr_list -- Optional list of headers to be sent with the
1669 message.
1670
1671 """
Benny Prijono55040452008-07-21 18:20:57 +00001672 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001673 err = _pjsua.call_reinvite(self._id, True,
1674 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001675 self._lib()._err_check("reinvite()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001676
1677 def update(self, hdr_list=None, options=0):
1678 """
1679 Send UPDATE and optionally offer new codecs to use.
1680
1681 Keyword arguments:
1682 hdr_list -- Optional list of headers to be sent with the
1683 message.
1684 options -- Must be zero for now.
1685
1686 """
Benny Prijono55040452008-07-21 18:20:57 +00001687 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001688 err = _pjsua.call_update(self._id, options,
1689 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001690 self._lib()._err_check("update()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001691
1692 def transfer(self, dest_uri, hdr_list=None):
1693 """
1694 Transfer the call to new destination.
1695
1696 Keyword arguments:
1697 dest_uri -- Specify the SIP URI to transfer the call to.
1698 hdr_list -- Optional list of headers to be sent with the
1699 message.
1700
1701 """
Benny Prijono55040452008-07-21 18:20:57 +00001702 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001703 err = _pjsua.call_xfer(self._id, dest_uri,
1704 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001705 self._lib()._err_check("transfer()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001706
1707 def transfer_to_call(self, call, hdr_list=None, options=0):
1708 """
1709 Attended call transfer.
1710
1711 Keyword arguments:
1712 call -- The Call object to transfer call to.
1713 hdr_list -- Optional list of headers to be sent with the
1714 message.
1715 options -- Must be zero for now.
1716
1717 """
Benny Prijono55040452008-07-21 18:20:57 +00001718 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001719 err = _pjsua.call_xfer_replaces(self._id, call._id, options,
1720 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001721 self._lib()._err_check("transfer_to_call()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001722
1723 def dial_dtmf(self, digits):
1724 """
1725 Send DTMF digits with RTP event package.
1726
1727 Keyword arguments:
1728 digits -- DTMF digit string.
1729
1730 """
Benny Prijono55040452008-07-21 18:20:57 +00001731 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001732 err = _pjsua.call_dial_dtmf(self._id, digits)
Benny Prijono55040452008-07-21 18:20:57 +00001733 self._lib()._err_check("dial_dtmf()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001734
1735 def send_request(self, method, hdr_list=None, content_type=None,
1736 body=None):
1737 """
1738 Send arbitrary request to remote call.
1739
1740 This is useful for example to send INFO request. Note that this
1741 function should not be used to send request that will change the
1742 call state such as CANCEL or BYE.
1743
1744 Keyword arguments:
1745 method -- SIP method name.
1746 hdr_list -- Optional header list to be sent with the request.
1747 content_type -- Content type to describe the body, if the body
1748 is present
1749 body -- Optional SIP message body.
1750
1751 """
Benny Prijono55040452008-07-21 18:20:57 +00001752 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001753 if hdr_list and body:
1754 msg_data = _pjsua.Msg_Data()
1755 if hdr_list:
1756 msg_data.hdr_list = hdr_list
1757 if content_type:
1758 msg_data.content_type = content_type
1759 if body:
1760 msg_data.msg_body = body
1761 else:
1762 msg_data = None
1763
1764 err = _pjsua.call_send_request(self._id, method, msg_data)
Benny Prijono55040452008-07-21 18:20:57 +00001765 self._lib()._err_check("send_request()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001766
1767
1768class BuddyInfo:
1769 """This class contains information about Buddy. Application may
1770 retrieve this information by calling Buddy.info().
Benny Prijonob85ba652008-07-11 00:55:22 +00001771
1772 Member documentation:
1773
1774 uri -- the Buddy URI.
1775 contact -- the Buddy Contact URI, if available.
1776 online_status -- the presence online status.
1777 online_text -- the presence online status text.
1778 activity -- the PresenceActivity
1779 subscribed -- specify whether buddy's presence status is currently
1780 being subscribed.
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001781 sub_state -- SubscriptionState
1782 sub_term_reason -- The termination reason string of the last presence
1783 subscription to this buddy, if any.
Benny Prijono9c461142008-07-10 22:41:20 +00001784 """
1785 uri = ""
1786 contact = ""
1787 online_status = 0
1788 online_text = ""
1789 activity = PresenceActivity.UNKNOWN
1790 subscribed = False
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001791 sub_state = SubscriptionState.NULL
1792 sub_term_reason = ""
Benny Prijono9c461142008-07-10 22:41:20 +00001793
1794 def __init__(self, pjsua_bi=None):
1795 if pjsua_bi:
1796 self._cvt_from_pjsua(pjsua_bi)
1797
1798 def _cvt_from_pjsua(self, inf):
1799 self.uri = inf.uri
1800 self.contact = inf.contact
1801 self.online_status = inf.status
1802 self.online_text = inf.status_text
1803 self.activity = inf.activity
1804 self.subscribed = inf.monitor_pres
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001805 self.sub_state = inf.sub_state
1806 self.sub_term_reason = inf.sub_term_reason
Benny Prijono9c461142008-07-10 22:41:20 +00001807
1808
1809class BuddyCallback:
1810 """This class can be used to receive notifications about Buddy's
1811 presence status change. Application needs to derive a class from
1812 this class, and register the instance with Buddy.set_callback().
Benny Prijonob85ba652008-07-11 00:55:22 +00001813
1814 Member documentation:
1815
1816 buddy -- the Buddy object.
Benny Prijono9c461142008-07-10 22:41:20 +00001817 """
1818 buddy = None
1819
Benny Prijono55040452008-07-21 18:20:57 +00001820 def __init__(self, buddy=None):
1821 self._set_buddy(buddy)
1822
1823 def _set_buddy(self, buddy):
1824 if buddy:
1825 self.buddy = weakref.proxy(buddy)
1826 else:
1827 self.buddy = None
Benny Prijono9c461142008-07-10 22:41:20 +00001828
1829 def on_state(self):
1830 """
1831 Notification that buddy's presence state has changed. Application
1832 may then retrieve the new status with Buddy.info() function.
1833 """
1834 pass
1835
1836 def on_pager(self, mime_type, body):
1837 """Notification that incoming instant message is received from
1838 this buddy.
1839
1840 Keyword arguments:
1841 mime_type -- MIME type of the instant message body
1842 body -- the instant message body
1843
1844 """
1845 pass
1846
1847 def on_pager_status(self, body, im_id, code, reason):
1848 """Notification about the delivery status of previously sent
1849 instant message.
1850
1851 Keyword arguments:
1852 body -- the message body
1853 im_id -- message ID
1854 code -- SIP status code
1855 reason -- SIP reason phrase
1856
1857 """
1858 pass
1859
1860 def on_typing(self, is_typing):
1861 """Notification that remote is typing or stop typing.
1862
1863 Keyword arguments:
1864 is_typing -- boolean to indicate whether remote is currently
1865 typing an instant message.
1866
1867 """
1868 pass
1869
1870
1871class Buddy:
1872 """A Buddy represents person or remote agent.
1873
1874 This class provides functions to subscribe to buddy's presence and
1875 to send or receive instant messages from the buddy.
1876 """
1877 _id = -1
1878 _lib = None
1879 _cb = None
1880 _obj_name = ""
1881 _acc = None
1882
Benny Prijono55040452008-07-21 18:20:57 +00001883 def __init__(self, lib, id, account, cb):
Benny Prijono9c461142008-07-10 22:41:20 +00001884 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +00001885 self._lib = weakref.ref(lib)
1886 self._acc = weakref.ref(account)
1887 self._obj_name = "{Buddy " + self.info().uri + "}"
1888 self.set_callback(cb)
1889 _pjsua.buddy_set_user_data(self._id, self)
1890 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001891
1892 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001893 if self._id != -1:
1894 _pjsua.buddy_set_user_data(self._id, 0)
1895 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001896
1897 def __str__(self):
1898 return self._obj_name
1899
1900 def info(self):
1901 """
1902 Get buddy info as BuddyInfo.
1903 """
Benny Prijono55040452008-07-21 18:20:57 +00001904 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001905 return BuddyInfo(_pjsua.buddy_get_info(self._id))
1906
1907 def set_callback(self, cb):
1908 """Install callback to receive notifications from this object.
1909
1910 Keyword argument:
1911 cb -- BuddyCallback instance.
1912 """
1913 if cb:
1914 self._cb = cb
1915 else:
1916 self._cb = BuddyCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001917 self._cb._set_buddy(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001918
1919 def subscribe(self):
1920 """
1921 Subscribe to buddy's presence status notification.
1922 """
Benny Prijono55040452008-07-21 18:20:57 +00001923 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001924 err = _pjsua.buddy_subscribe_pres(self._id, True)
Benny Prijono55040452008-07-21 18:20:57 +00001925 self._lib()._err_check("subscribe()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001926
1927 def unsubscribe(self):
1928 """
1929 Unsubscribe from buddy's presence status notification.
1930 """
Benny Prijono55040452008-07-21 18:20:57 +00001931 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001932 err = _pjsua.buddy_subscribe_pres(self._id, False)
Benny Prijono55040452008-07-21 18:20:57 +00001933 self._lib()._err_check("unsubscribe()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001934
1935 def delete(self):
1936 """
1937 Remove this buddy from the buddy list.
1938 """
Benny Prijono55040452008-07-21 18:20:57 +00001939 lck = self._lib().auto_lock()
1940 if self._id != -1:
1941 _pjsua.buddy_set_user_data(self._id, 0)
Benny Prijono9c461142008-07-10 22:41:20 +00001942 err = _pjsua.buddy_del(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001943 self._lib()._err_check("delete()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001944
1945 def send_pager(self, text, im_id=0, content_type="text/plain", \
1946 hdr_list=None):
1947 """Send instant message to remote buddy.
1948
1949 Keyword arguments:
1950 text -- Instant message to be sent
1951 im_id -- Optional instant message ID to identify this
1952 instant message when delivery status callback
1953 is called.
1954 content_type -- MIME type identifying the instant message
1955 hdr_list -- Optional list of headers to be sent with the
1956 request.
1957
1958 """
Benny Prijono55040452008-07-21 18:20:57 +00001959 lck = self._lib().auto_lock()
1960 err = _pjsua.im_send(self._acc()._id, self.info().uri, \
Benny Prijono9c461142008-07-10 22:41:20 +00001961 content_type, text, \
1962 Lib._create_msg_data(hdr_list), \
1963 im_id)
Benny Prijono55040452008-07-21 18:20:57 +00001964 self._lib()._err_check("send_pager()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001965
1966 def send_typing_ind(self, is_typing=True, hdr_list=None):
1967 """Send typing indication to remote buddy.
1968
1969 Keyword argument:
1970 is_typing -- boolean to indicate wheter user is typing.
1971 hdr_list -- Optional list of headers to be sent with the
1972 request.
1973
1974 """
Benny Prijono55040452008-07-21 18:20:57 +00001975 lck = self._lib().auto_lock()
1976 err = _pjsua.im_typing(self._acc()._id, self.info().uri, \
Benny Prijono9c461142008-07-10 22:41:20 +00001977 is_typing, Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001978 self._lib()._err_check("send_typing_ind()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001979
1980
1981
1982# Sound device info
1983class SoundDeviceInfo:
Benny Prijonob85ba652008-07-11 00:55:22 +00001984 """This described the sound device info.
1985
1986 Member documentation:
1987 name -- device name.
1988 input_channels -- number of capture channels supported.
1989 output_channels -- number of playback channels supported.
1990 default_clock_rate -- default sampling rate.
1991 """
Benny Prijono9c461142008-07-10 22:41:20 +00001992 name = ""
1993 input_channels = 0
Benny Prijonob85ba652008-07-11 00:55:22 +00001994 output_channels = 0
Benny Prijono9c461142008-07-10 22:41:20 +00001995 default_clock_rate = 0
1996
1997 def __init__(self, sdi):
1998 self.name = sdi.name
1999 self.input_channels = sdi.input_count
2000 self.output_channels = sdi.output_count
2001 self.default_clock_rate = sdi.default_samples_per_sec
2002
2003
2004# Codec info
2005class CodecInfo:
Benny Prijonob85ba652008-07-11 00:55:22 +00002006 """This describes codec info.
2007
2008 Member documentation:
2009 name -- codec name
2010 priority -- codec priority (0-255)
2011 clock_rate -- clock rate
2012 channel_count -- number of channels
2013 avg_bps -- average bandwidth in bits per second
2014 frm_ptime -- base frame length in milliseconds
2015 ptime -- RTP frame length in milliseconds.
2016 pt -- payload type.
2017 vad_enabled -- specify if Voice Activity Detection is currently
2018 enabled.
2019 plc_enabled -- specify if Packet Lost Concealment is currently
2020 enabled.
2021 """
Benny Prijono9c461142008-07-10 22:41:20 +00002022 name = ""
2023 priority = 0
2024 clock_rate = 0
2025 channel_count = 0
2026 avg_bps = 0
2027 frm_ptime = 0
2028 ptime = 0
2029 pt = 0
2030 vad_enabled = False
2031 plc_enabled = False
2032
2033 def __init__(self, codec_info, codec_param):
2034 self.name = codec_info.id
2035 self.priority = codec_info.priority
2036 self.clock_rate = codec_param.info.clock_rate
2037 self.channel_count = codec_param.info.channel_count
2038 self.avg_bps = codec_param.info.avg_bps
2039 self.frm_ptime = codec_param.info.frm_ptime
2040 self.ptime = codec_param.info.frm_ptime * \
2041 codec_param.setting.frm_per_pkt
2042 self.ptime = codec_param.info.pt
2043 self.vad_enabled = codec_param.setting.vad
2044 self.plc_enabled = codec_param.setting.plc
2045
2046 def _cvt_to_pjsua(self):
2047 ci = _pjsua.Codec_Info()
2048 ci.id = self.name
2049 ci.priority = self.priority
2050 return ci
2051
2052
2053# Codec parameter
2054class CodecParameter:
Benny Prijonob85ba652008-07-11 00:55:22 +00002055 """This specifies various parameters that can be configured for codec.
2056
2057 Member documentation:
2058
2059 ptime -- specify the outgoing RTP packet length in milliseconds.
2060 vad_enabled -- specify if VAD should be enabled.
2061 plc_enabled -- specify if PLC should be enabled.
2062 """
Benny Prijono9c461142008-07-10 22:41:20 +00002063 ptime = 0
2064 vad_enabled = False
2065 plc_enabled = False
2066 _codec_param = None
2067
2068 def __init__(self, codec_param):
2069 self.ptime = codec_param.info.frm_ptime * \
2070 codec_param.setting.frm_per_pkt
2071 self.vad_enabled = codec_param.setting.vad
2072 self.plc_enabled = codec_param.setting.plc
2073 self._codec_param = codec_param
2074
2075 def _cvt_to_pjsua(self):
2076 self._codec_param.setting.frm_per_pkt = self.ptime / \
2077 self._codec_param.info.frm_ptime
2078 self._codec_param.setting.vad = self.vad_enabled
2079 self._codec_param.setting.plc = self.plc_enabled
2080 return self._codec_param
2081
2082
Benny Prijono55040452008-07-21 18:20:57 +00002083# Library mutex
2084class _LibMutex:
2085 def __init__(self, lck):
2086 self._lck = lck
2087 self._lck.acquire()
Benny Prijono6ecef072008-07-21 22:46:35 +00002088 #_Trace(('lock acquired',))
Benny Prijono55040452008-07-21 18:20:57 +00002089
2090 def __del__(self):
Benny Prijono6ecef072008-07-21 22:46:35 +00002091 try:
2092 self._lck.release()
2093 #_Trace(('lock released',))
2094 except:
2095 #_Trace(('lock release error',))
2096 pass
Benny Prijono55040452008-07-21 18:20:57 +00002097
2098
Benny Prijono9c461142008-07-10 22:41:20 +00002099# PJSUA Library
2100_lib = None
2101class Lib:
2102 """Library instance.
2103
2104 """
Benny Prijono9c461142008-07-10 22:41:20 +00002105 _quit = False
2106 _has_thread = False
Benny Prijono55040452008-07-21 18:20:57 +00002107 _lock = None
Benny Prijono9c461142008-07-10 22:41:20 +00002108
2109 def __init__(self):
2110 global _lib
2111 if _lib:
2112 raise Error("__init()__", None, -1,
2113 "Library instance already exist")
Benny Prijono55040452008-07-21 18:20:57 +00002114
2115 self._lock = threading.RLock()
Benny Prijono9c461142008-07-10 22:41:20 +00002116 err = _pjsua.create()
2117 self._err_check("_pjsua.create()", None, err)
2118 _lib = self
2119
2120 def __del__(self):
2121 _pjsua.destroy()
Benny Prijono55040452008-07-21 18:20:57 +00002122 del self._lock
Benny Prijono6ecef072008-07-21 22:46:35 +00002123 _Trace(('Lib destroyed',))
Benny Prijono9c461142008-07-10 22:41:20 +00002124
2125 def __str__(self):
2126 return "Lib"
2127
2128 @staticmethod
2129 def instance():
2130 """Return singleton instance of Lib.
2131 """
2132 return _lib
2133
2134 def init(self, ua_cfg=None, log_cfg=None, media_cfg=None):
2135 """
2136 Initialize pjsua with the specified configurations.
2137
2138 Keyword arguments:
2139 ua_cfg -- optional UAConfig instance
2140 log_cfg -- optional LogConfig instance
2141 media_cfg -- optional MediaConfig instance
2142
2143 """
2144 if not ua_cfg: ua_cfg = UAConfig()
2145 if not log_cfg: log_cfg = LogConfig()
2146 if not media_cfg: media_cfg = MediaConfig()
2147
2148 py_ua_cfg = ua_cfg._cvt_to_pjsua()
2149 py_ua_cfg.cb.on_call_state = _cb_on_call_state
2150 py_ua_cfg.cb.on_incoming_call = _cb_on_incoming_call
2151 py_ua_cfg.cb.on_call_media_state = _cb_on_call_media_state
2152 py_ua_cfg.cb.on_dtmf_digit = _cb_on_dtmf_digit
2153 py_ua_cfg.cb.on_call_transfer_request = _cb_on_call_transfer_request
2154 py_ua_cfg.cb.on_call_transfer_status = _cb_on_call_transfer_status
2155 py_ua_cfg.cb.on_call_replace_request = _cb_on_call_replace_request
2156 py_ua_cfg.cb.on_call_replaced = _cb_on_call_replaced
2157 py_ua_cfg.cb.on_reg_state = _cb_on_reg_state
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002158 py_ua_cfg.cb.on_incoming_subscribe = _cb_on_incoming_subscribe
Benny Prijono9c461142008-07-10 22:41:20 +00002159 py_ua_cfg.cb.on_buddy_state = _cb_on_buddy_state
2160 py_ua_cfg.cb.on_pager = _cb_on_pager
2161 py_ua_cfg.cb.on_pager_status = _cb_on_pager_status
2162 py_ua_cfg.cb.on_typing = _cb_on_typing
2163
2164 err = _pjsua.init(py_ua_cfg, log_cfg._cvt_to_pjsua(),
Benny Prijono55040452008-07-21 18:20:57 +00002165 media_cfg._cvt_to_pjsua())
Benny Prijono9c461142008-07-10 22:41:20 +00002166 self._err_check("init()", self, err)
2167
2168 def destroy(self):
2169 """Destroy the library, and pjsua."""
2170 global _lib
2171 if self._has_thread:
2172 self._quit = 1
2173 loop = 0
2174 while self._quit != 2 and loop < 400:
Benny Prijono6ecef072008-07-21 22:46:35 +00002175 self.handle_events(5)
Benny Prijono9c461142008-07-10 22:41:20 +00002176 loop = loop + 1
Benny Prijono6ecef072008-07-21 22:46:35 +00002177 time.sleep(0.050)
Benny Prijono9c461142008-07-10 22:41:20 +00002178 _pjsua.destroy()
2179 _lib = None
Benny Prijono55040452008-07-21 18:20:57 +00002180
Benny Prijono9c461142008-07-10 22:41:20 +00002181 def start(self, with_thread=True):
2182 """Start the library.
2183
2184 Keyword argument:
2185 with_thread -- specify whether the module should create worker
2186 thread.
2187
2188 """
Benny Prijono6ecef072008-07-21 22:46:35 +00002189 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002190 err = _pjsua.start()
2191 self._err_check("start()", self, err)
2192 self._has_thread = with_thread
2193 if self._has_thread:
2194 thread.start_new(_worker_thread_main, (0,))
2195
2196 def handle_events(self, timeout=50):
2197 """Poll the events from underlying pjsua library.
2198
2199 Application must poll the stack periodically if worker thread
2200 is disable when starting the library.
2201
2202 Keyword argument:
2203 timeout -- in milliseconds.
2204
2205 """
Benny Prijono55040452008-07-21 18:20:57 +00002206 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002207 return _pjsua.handle_events(timeout)
2208
2209 def verify_sip_url(self, sip_url):
2210 """Verify that the specified string is a valid URI.
2211
2212 Keyword argument:
2213 sip_url -- the URL string.
2214
2215 Return:
2216 0 is the the URI is valid, otherwise the appropriate error
2217 code is returned.
2218
2219 """
Benny Prijono55040452008-07-21 18:20:57 +00002220 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002221 return _pjsua.verify_sip_url(sip_url)
2222
2223 def create_transport(self, type, cfg=None):
2224 """Create SIP transport instance of the specified type.
2225
2226 Keyword arguments:
2227 type -- transport type from TransportType constant.
2228 cfg -- TransportConfig instance
2229
2230 Return:
2231 Transport object
2232
2233 """
Benny Prijono55040452008-07-21 18:20:57 +00002234 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002235 if not cfg: cfg=TransportConfig(type)
2236 err, tp_id = _pjsua.transport_create(type, cfg._cvt_to_pjsua())
2237 self._err_check("create_transport()", self, err)
2238 return Transport(self, tp_id)
2239
Benny Prijono55040452008-07-21 18:20:57 +00002240 def create_account(self, acc_config, set_default=True, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00002241 """
2242 Create a new local pjsua account using the specified configuration.
2243
2244 Keyword arguments:
2245 acc_config -- AccountConfig
2246 set_default -- boolean to specify whether to use this as the
2247 default account.
Benny Prijono55040452008-07-21 18:20:57 +00002248 cb -- AccountCallback instance.
Benny Prijono9c461142008-07-10 22:41:20 +00002249
2250 Return:
2251 Account instance
2252
2253 """
Benny Prijono55040452008-07-21 18:20:57 +00002254 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002255 err, acc_id = _pjsua.acc_add(acc_config._cvt_to_pjsua(), set_default)
2256 self._err_check("create_account()", self, err)
Benny Prijono55040452008-07-21 18:20:57 +00002257 return Account(self, acc_id, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00002258
Benny Prijono55040452008-07-21 18:20:57 +00002259 def create_account_for_transport(self, transport, set_default=True,
2260 cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00002261 """Create a new local pjsua transport for the specified transport.
2262
2263 Keyword arguments:
2264 transport -- the Transport instance.
2265 set_default -- boolean to specify whether to use this as the
2266 default account.
Benny Prijono55040452008-07-21 18:20:57 +00002267 cb -- AccountCallback instance.
Benny Prijono9c461142008-07-10 22:41:20 +00002268
2269 Return:
2270 Account instance
2271
2272 """
Benny Prijono55040452008-07-21 18:20:57 +00002273 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002274 err, acc_id = _pjsua.acc_add_local(transport._id, set_default)
2275 self._err_check("create_account_for_transport()", self, err)
Benny Prijono55040452008-07-21 18:20:57 +00002276 return Account(self, acc_id, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00002277
2278 def hangup_all(self):
2279 """Hangup all calls.
2280
2281 """
Benny Prijono55040452008-07-21 18:20:57 +00002282 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002283 _pjsua.call_hangup_all()
2284
2285 # Sound device API
2286
2287 def enum_snd_dev(self):
2288 """Enumerate sound devices in the system.
2289
2290 Return:
Benny Prijono288d4bd2008-07-19 15:40:21 +00002291 list of SoundDeviceInfo. The index of the element specifies
Benny Prijono9c461142008-07-10 22:41:20 +00002292 the device ID for the device.
2293 """
Benny Prijono55040452008-07-21 18:20:57 +00002294 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002295 sdi_list = _pjsua.enum_snd_devs()
Benny Prijono9c461142008-07-10 22:41:20 +00002296 info = []
Benny Prijono288d4bd2008-07-19 15:40:21 +00002297 for sdi in sdi_list:
Benny Prijono9c461142008-07-10 22:41:20 +00002298 info.append(SoundDeviceInfo(sdi))
2299 return info
2300
2301 def get_snd_dev(self):
2302 """Get the device IDs of current sound devices used by pjsua.
2303
2304 Return:
2305 (capture_dev_id, playback_dev_id) tuple
2306 """
Benny Prijono55040452008-07-21 18:20:57 +00002307 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002308 return _pjsua.get_snd_dev()
2309
2310 def set_snd_dev(self, capture_dev, playback_dev):
2311 """Change the current sound devices.
2312
2313 Keyword arguments:
2314 capture_dev -- the device ID of capture device to be used
2315 playback_dev -- the device ID of playback device to be used.
2316
2317 """
Benny Prijono55040452008-07-21 18:20:57 +00002318 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002319 err = _pjsua.set_snd_dev(capture_dev, playback_dev)
2320 self._err_check("set_current_sound_devices()", self, err)
2321
2322 def set_null_snd_dev(self):
2323 """Disable the sound devices. This is useful if the system
2324 does not have sound device installed.
2325
2326 """
Benny Prijono55040452008-07-21 18:20:57 +00002327 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002328 err = _pjsua.set_null_snd_dev()
2329 self._err_check("set_null_snd_dev()", self, err)
2330
2331
2332 # Conference bridge
2333
2334 def conf_get_max_ports(self):
2335 """Get the conference bridge capacity.
2336
2337 Return:
2338 conference bridge capacity.
2339
2340 """
Benny Prijono55040452008-07-21 18:20:57 +00002341 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002342 return _pjsua.conf_get_max_ports()
2343
2344 def conf_connect(self, src_slot, dst_slot):
2345 """Establish unidirectional media flow from souce to sink.
2346
2347 One source may transmit to multiple destinations/sink. And if
2348 multiple sources are transmitting to the same sink, the media
2349 will be mixed together. Source and sink may refer to the same ID,
2350 effectively looping the media.
2351
2352 If bidirectional media flow is desired, application needs to call
2353 this function twice, with the second one having the arguments
2354 reversed.
2355
2356 Keyword arguments:
2357 src_slot -- integer to identify the conference slot number of
2358 the source/transmitter.
2359 dst_slot -- integer to identify the conference slot number of
2360 the destination/receiver.
2361
2362 """
Benny Prijono55040452008-07-21 18:20:57 +00002363 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002364 err = _pjsua.conf_connect(src_slot, dst_slot)
2365 self._err_check("conf_connect()", self, err)
2366
2367 def conf_disconnect(self, src_slot, dst_slot):
2368 """Disconnect media flow from the source to destination port.
2369
2370 Keyword arguments:
2371 src_slot -- integer to identify the conference slot number of
2372 the source/transmitter.
2373 dst_slot -- integer to identify the conference slot number of
2374 the destination/receiver.
2375
2376 """
Benny Prijono55040452008-07-21 18:20:57 +00002377 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002378 err = _pjsua.conf_disconnect(src_slot, dst_slot)
2379 self._err_check("conf_disconnect()", self, err)
2380
Benny Prijono288d4bd2008-07-19 15:40:21 +00002381 def conf_set_tx_level(self, slot, level):
2382 """Adjust the signal level to be transmitted from the bridge to
2383 the specified port by making it louder or quieter.
2384
2385 Keyword arguments:
2386 slot -- integer to identify the conference slot number.
2387 level -- Signal level adjustment. Value 1.0 means no level
2388 adjustment, while value 0 means to mute the port.
2389 """
Benny Prijono55040452008-07-21 18:20:57 +00002390 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002391 err = _pjsua.conf_set_tx_level(slot, level)
2392 self._err_check("conf_set_tx_level()", self, err)
2393
2394 def conf_set_rx_level(self, slot, level):
2395 """Adjust the signal level to be received from the specified port
2396 (to the bridge) by making it louder or quieter.
2397
2398 Keyword arguments:
2399 slot -- integer to identify the conference slot number.
2400 level -- Signal level adjustment. Value 1.0 means no level
2401 adjustment, while value 0 means to mute the port.
2402 """
Benny Prijono55040452008-07-21 18:20:57 +00002403 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002404 err = _pjsua.conf_set_rx_level(slot, level)
2405 self._err_check("conf_set_rx_level()", self, err)
2406
2407 def conf_get_signal_level(self, slot):
2408 """Get last signal level transmitted to or received from the
2409 specified port. The signal levels are float values from 0.0 to 1.0,
2410 with 0.0 indicates no signal, and 1.0 indicates the loudest signal
2411 level.
2412
2413 Keyword arguments:
2414 slot -- integer to identify the conference slot number.
2415
2416 Return value:
2417 (tx_level, rx_level) tuple.
2418 """
Benny Prijono55040452008-07-21 18:20:57 +00002419 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002420 err, tx_level, rx_level = _pjsua.conf_get_signal_level(slot)
2421 self._err_check("conf_get_signal_level()", self, err)
2422 return (tx_level, rx_level)
2423
2424
2425
Benny Prijono9c461142008-07-10 22:41:20 +00002426 # Codecs API
2427
2428 def enum_codecs(self):
2429 """Return list of codecs supported by pjsua.
2430
2431 Return:
Benny Prijono288d4bd2008-07-19 15:40:21 +00002432 list of CodecInfo
Benny Prijono9c461142008-07-10 22:41:20 +00002433
2434 """
Benny Prijono55040452008-07-21 18:20:57 +00002435 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002436 ci_list = _pjsua.enum_codecs()
Benny Prijono9c461142008-07-10 22:41:20 +00002437 codec_info = []
Benny Prijono288d4bd2008-07-19 15:40:21 +00002438 for ci in ci_list:
Benny Prijono9c461142008-07-10 22:41:20 +00002439 cp = _pjsua.codec_get_param(ci.id)
2440 if cp:
2441 codec_info.append(CodecInfo(ci, cp))
2442 return codec_info
2443
2444 def set_codec_priority(self, name, priority):
2445 """Change the codec priority.
2446
2447 Keyword arguments:
2448 name -- Codec name
2449 priority -- Codec priority, which range is 0-255.
2450
2451 """
Benny Prijono55040452008-07-21 18:20:57 +00002452 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002453 err = _pjsua.codec_set_priority(name, priority)
2454 self._err_check("set_codec_priority()", self, err)
2455
2456 def get_codec_parameter(self, name):
2457 """Get codec parameter for the specified codec.
2458
2459 Keyword arguments:
2460 name -- codec name.
2461
2462 """
Benny Prijono55040452008-07-21 18:20:57 +00002463 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002464 cp = _pjsua.codec_get_param(name)
2465 if not cp:
2466 self._err_check("get_codec_parameter()", self, -1,
2467 "Invalid codec name")
2468 return CodecParameter(cp)
2469
2470 def set_codec_parameter(self, name, param):
2471 """Modify codec parameter for the specified codec.
2472
2473 Keyword arguments:
2474 name -- codec name
2475 param -- codec parameter.
2476
2477 """
Benny Prijono55040452008-07-21 18:20:57 +00002478 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002479 err = _pjsua.codec_set_param(name, param._cvt_to_pjsua())
2480 self._err_check("set_codec_parameter()", self, err)
2481
2482 # WAV playback and recording
2483
2484 def create_player(self, filename, loop=False):
2485 """Create WAV file player.
2486
2487 Keyword arguments
2488 filename -- WAV file name
Benny Prijono288d4bd2008-07-19 15:40:21 +00002489 loop -- boolean to specify whether playback should
2490 automatically restart upon EOF
Benny Prijono9c461142008-07-10 22:41:20 +00002491 Return:
2492 WAV player ID
2493
2494 """
Benny Prijono55040452008-07-21 18:20:57 +00002495 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002496 opt = 0
2497 if not loop:
2498 opt = opt + 1
2499 err, player_id = _pjsua.player_create(filename, opt)
2500 self._err_check("create_player()", self, err)
2501 return player_id
2502
2503 def player_get_slot(self, player_id):
2504 """Get the conference port ID for the specified player.
2505
2506 Keyword arguments:
2507 player_id -- the WAV player ID
2508
2509 Return:
2510 Conference slot number for the player
2511
2512 """
Benny Prijono55040452008-07-21 18:20:57 +00002513 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002514 slot = _pjsua.player_get_conf_port(player_id)
Benny Prijono940bd3e2008-07-11 09:14:40 +00002515 if slot < 0:
2516 self._err_check("player_get_slot()", self, -1,
2517 "Invalid player id")
Benny Prijono9c461142008-07-10 22:41:20 +00002518 return slot
2519
2520 def player_set_pos(self, player_id, pos):
2521 """Set WAV playback position.
2522
2523 Keyword arguments:
2524 player_id -- WAV player ID
2525 pos -- playback position, in samples
2526
2527 """
Benny Prijono55040452008-07-21 18:20:57 +00002528 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002529 err = _pjsua.player_set_pos(player_id, pos)
2530 self._err_check("player_set_pos()", self, err)
2531
2532 def player_destroy(self, player_id):
2533 """Destroy the WAV player.
2534
2535 Keyword arguments:
2536 player_id -- the WAV player ID.
2537
2538 """
Benny Prijono55040452008-07-21 18:20:57 +00002539 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002540 err = _pjsua.player_destroy(player_id)
2541 self._err_check("player_destroy()", self, err)
2542
Benny Prijono288d4bd2008-07-19 15:40:21 +00002543 def create_playlist(self, filelist, label="playlist", loop=True):
2544 """Create WAV playlist.
2545
2546 Keyword arguments:
2547 filelist -- List of WAV file names.
2548 label -- Optional name to be assigned to the playlist
2549 object (useful for logging)
2550 loop -- boolean to specify whether playback should
2551 automatically restart upon EOF
2552
2553 Return:
2554 playlist_id
2555 """
Benny Prijono55040452008-07-21 18:20:57 +00002556 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002557 opt = 0
2558 if not loop:
2559 opt = opt + 1
2560 err, playlist_id = _pjsua.playlist_create(label, filelist, opt)
2561 self._err_check("create_playlist()", self, err)
2562 return playlist_id
2563
2564 def playlist_get_slot(self, playlist_id):
2565 """Get the conference port ID for the specified playlist.
2566
2567 Keyword arguments:
2568 playlist_id -- the WAV playlist ID
2569
2570 Return:
2571 Conference slot number for the playlist
2572
2573 """
Benny Prijono55040452008-07-21 18:20:57 +00002574 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002575 slot = _pjsua.player_get_conf_port(playlist_id)
2576 if slot < 0:
2577 self._err_check("playlist_get_slot()", self, -1,
2578 "Invalid playlist id")
2579 return slot
2580
2581 def playlist_destroy(self, playlist_id):
2582 """Destroy the WAV playlist.
2583
2584 Keyword arguments:
2585 playlist_id -- the WAV playlist ID.
2586
2587 """
Benny Prijono55040452008-07-21 18:20:57 +00002588 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002589 err = _pjsua.player_destroy(playlist_id)
2590 self._err_check("playlist_destroy()", self, err)
2591
Benny Prijono9c461142008-07-10 22:41:20 +00002592 def create_recorder(self, filename):
2593 """Create WAV file recorder.
2594
2595 Keyword arguments
2596 filename -- WAV file name
2597
2598 Return:
2599 WAV recorder ID
2600
2601 """
Benny Prijono55040452008-07-21 18:20:57 +00002602 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002603 err, rec_id = _pjsua.recorder_create(filename, 0, None, -1, 0)
2604 self._err_check("create_recorder()", self, err)
2605 return rec_id
2606
2607 def recorder_get_slot(self, rec_id):
2608 """Get the conference port ID for the specified recorder.
2609
2610 Keyword arguments:
2611 rec_id -- the WAV recorder ID
2612
2613 Return:
2614 Conference slot number for the recorder
2615
2616 """
Benny Prijono55040452008-07-21 18:20:57 +00002617 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002618 slot = _pjsua.recorder_get_conf_port(rec_id)
Benny Prijono940bd3e2008-07-11 09:14:40 +00002619 if slot < 1:
2620 self._err_check("recorder_get_slot()", self, -1,
2621 "Invalid recorder id")
Benny Prijono9c461142008-07-10 22:41:20 +00002622 return slot
2623
2624 def recorder_destroy(self, rec_id):
2625 """Destroy the WAV recorder.
2626
2627 Keyword arguments:
2628 rec_id -- the WAV recorder ID.
2629
2630 """
Benny Prijono55040452008-07-21 18:20:57 +00002631 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002632 err = _pjsua.recorder_destroy(rec_id)
2633 self._err_check("recorder_destroy()", self, err)
2634
2635
2636 # Internal functions
2637
2638 @staticmethod
2639 def strerror(err):
2640 return _pjsua.strerror(err)
2641
2642 def _err_check(self, op_name, obj, err_code, err_msg=""):
2643 if err_code != 0:
2644 raise Error(op_name, obj, err_code, err_msg)
2645
2646 @staticmethod
2647 def _create_msg_data(hdr_list):
2648 if not hdr_list:
2649 return None
2650 msg_data = _pjsua.Msg_Data()
2651 msg_data.hdr_list = hdr_list
2652 return msg_data
2653
Benny Prijono55040452008-07-21 18:20:57 +00002654 def auto_lock(self):
2655 return _LibMutex(self._lock)
2656
Benny Prijono9c461142008-07-10 22:41:20 +00002657 # Internal dictionary manipulation for calls, accounts, and buddies
2658
Benny Prijono9c461142008-07-10 22:41:20 +00002659 def _lookup_call(self, call_id):
Benny Prijono55040452008-07-21 18:20:57 +00002660 return _pjsua.call_get_user_data(call_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002661
2662 def _lookup_account(self, acc_id):
Benny Prijono55040452008-07-21 18:20:57 +00002663 return _pjsua.acc_get_user_data(acc_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002664
2665 def _lookup_buddy(self, buddy_id, uri=None):
Benny Prijono55040452008-07-21 18:20:57 +00002666 if buddy_id != -1:
2667 buddy = _pjsua.buddy_get_user_data(buddy_id)
2668 elif uri:
2669 buddy_id = _pjsua.buddy_find(uri)
2670 if buddy_id != -1:
2671 buddy = _pjsua.buddy_get_user_data(buddy_id)
2672 else:
2673 buddy = None
2674 else:
2675 buddy = None
2676
Benny Prijono9c461142008-07-10 22:41:20 +00002677 return buddy
2678
Benny Prijono9c461142008-07-10 22:41:20 +00002679 # Account allbacks
2680
2681 def _cb_on_reg_state(self, acc_id):
2682 acc = self._lookup_account(acc_id)
2683 if acc:
2684 acc._cb.on_reg_state()
2685
Benny Prijono55040452008-07-21 18:20:57 +00002686 def _cb_on_incoming_subscribe(self, acc_id, buddy_id, from_uri,
2687 contact_uri, pres_obj):
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002688 acc = self._lookup_account(acc_id)
2689 if acc:
2690 buddy = self._lookup_buddy(buddy_id)
Benny Prijono55040452008-07-21 18:20:57 +00002691 return acc._cb.on_incoming_subscribe(buddy, from_uri, contact_uri,
2692 pres_obj)
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002693 else:
2694 return (404, None)
2695
Benny Prijono9c461142008-07-10 22:41:20 +00002696 def _cb_on_incoming_call(self, acc_id, call_id, rdata):
2697 acc = self._lookup_account(acc_id)
2698 if acc:
2699 acc._cb.on_incoming_call( Call(self, call_id) )
2700 else:
2701 _pjsua.call_hangup(call_id, 603, None, None)
2702
2703 # Call callbacks
2704
2705 def _cb_on_call_state(self, call_id):
2706 call = self._lookup_call(call_id)
2707 if call:
Benny Prijono55040452008-07-21 18:20:57 +00002708 if call._id == -1:
2709 call.attach_to_id(call_id)
2710 done = (call.info().state == CallState.DISCONNECTED)
Benny Prijono9c461142008-07-10 22:41:20 +00002711 call._cb.on_state()
Benny Prijono55040452008-07-21 18:20:57 +00002712 if done:
2713 _pjsua.call_set_user_data(call_id, 0)
2714 else:
2715 pass
Benny Prijono9c461142008-07-10 22:41:20 +00002716
2717 def _cb_on_call_media_state(self, call_id):
2718 call = self._lookup_call(call_id)
2719 if call:
2720 call._cb.on_media_state()
2721
2722 def _cb_on_dtmf_digit(self, call_id, digits):
2723 call = self._lookup_call(call_id)
2724 if call:
2725 call._cb.on_dtmf_digit(digits)
2726
2727 def _cb_on_call_transfer_request(self, call_id, dst, code):
2728 call = self._lookup_call(call_id)
2729 if call:
2730 return call._cb.on_transfer_request(dst, code)
2731 else:
2732 return 603
2733
2734 def _cb_on_call_transfer_status(self, call_id, code, text, final, cont):
2735 call = self._lookup_call(call_id)
2736 if call:
2737 return call._cb.on_transfer_status(code, text, final, cont)
2738 else:
2739 return cont
2740
2741 def _cb_on_call_replace_request(self, call_id, rdata, code, reason):
2742 call = self._lookup_call(call_id)
2743 if call:
2744 return call._cb.on_replace_request(code, reason)
2745 else:
2746 return code, reason
2747
2748 def _cb_on_call_replaced(self, old_call_id, new_call_id):
2749 old_call = self._lookup_call(old_call_id)
2750 new_call = self._lookup_call(new_call_id)
2751 if old_call and new_call:
2752 old_call._cb.on_replaced(new_call)
2753
2754 def _cb_on_pager(self, call_id, from_uri, to_uri, contact, mime_type,
2755 body, acc_id):
2756 call = None
2757 if call_id == -1:
2758 call = self._lookup_call(call_id)
2759 if call:
2760 call._cb.on_pager(mime_type, body)
2761 else:
2762 acc = self._lookup_account(acc_id)
2763 buddy = self._lookup_buddy(-1, from_uri)
2764 if buddy:
2765 buddy._cb.on_pager(mime_type, body)
2766 else:
2767 acc._cb.on_pager(from_uri, contact, mime_type, body)
2768
2769 def _cb_on_pager_status(self, call_id, to_uri, body, user_data,
2770 code, reason, acc_id):
2771 call = None
2772 if call_id == -1:
2773 call = self._lookup_call(call_id)
2774 if call:
2775 call._cb.on_pager_status(body, user_data, code, reason)
2776 else:
2777 acc = self._lookup_account(acc_id)
2778 buddy = self._lookup_buddy(-1, to_uri)
2779 if buddy:
2780 buddy._cb.on_pager_status(body, user_data, code, reason)
2781 else:
2782 acc._cb.on_pager_status(to_uri, body, user_data, code, reason)
2783
2784 def _cb_on_typing(self, call_id, from_uri, to_uri, contact, is_typing,
2785 acc_id):
2786 call = None
2787 if call_id == -1:
2788 call = self._lookup_call(call_id)
2789 if call:
2790 call._cb.on_typing(is_typing)
2791 else:
2792 acc = self._lookup_account(acc_id)
2793 buddy = self._lookup_buddy(-1, from_uri)
2794 if buddy:
2795 buddy._cb.on_typing(is_typing)
2796 else:
2797 acc._cb.on_typing(from_uri, contact, is_typing)
2798
2799 def _cb_on_buddy_state(self, buddy_id):
2800 buddy = self._lookup_buddy(buddy_id)
2801 if buddy:
2802 buddy._cb.on_state()
2803
2804
2805
2806
2807#
2808# Internal
2809#
2810
2811def _cb_on_call_state(call_id, e):
2812 _lib._cb_on_call_state(call_id)
2813
2814def _cb_on_incoming_call(acc_id, call_id, rdata):
2815 _lib._cb_on_incoming_call(acc_id, call_id, rdata)
2816
2817def _cb_on_call_media_state(call_id):
2818 _lib._cb_on_call_media_state(call_id)
2819
2820def _cb_on_dtmf_digit(call_id, digits):
2821 _lib._cb_on_dtmf_digit(call_id, digits)
2822
2823def _cb_on_call_transfer_request(call_id, dst, code):
2824 return _lib._cb_on_call_transfer_request(call_id, dst, code)
2825
2826def _cb_on_call_transfer_status(call_id, code, reason, final, cont):
2827 return _lib._cb_on_call_transfer_status(call_id, code, reason,
2828 final, cont)
2829def _cb_on_call_replace_request(call_id, rdata, code, reason):
2830 return _lib._cb_on_call_replace_request(call_id, rdata, code, reason)
2831
2832def _cb_on_call_replaced(old_call_id, new_call_id):
2833 _lib._cb_on_call_replaced(old_call_id, new_call_id)
2834
2835def _cb_on_reg_state(acc_id):
2836 _lib._cb_on_reg_state(acc_id)
2837
Benny Prijono55040452008-07-21 18:20:57 +00002838def _cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, contact_uri, pres):
2839 return _lib._cb_on_incoming_subscribe(acc_id, buddy_id, from_uri,
2840 contact_uri, pres)
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002841
Benny Prijono9c461142008-07-10 22:41:20 +00002842def _cb_on_buddy_state(buddy_id):
2843 _lib._cb_on_buddy_state(buddy_id)
2844
2845def _cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id):
2846 _lib._cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id)
2847
2848def _cb_on_pager_status(call_id, to, body, user_data, status, reason, acc_id):
2849 _lib._cb_on_pager_status(call_id, to, body, user_data,
2850 status, reason, acc_id)
2851
2852def _cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id):
2853 _lib._cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id)
2854
2855
2856# Worker thread
2857def _worker_thread_main(arg):
2858 global _lib
Benny Prijono6ecef072008-07-21 22:46:35 +00002859 _Trace(('worker thread started..',))
Benny Prijono9c461142008-07-10 22:41:20 +00002860 thread_desc = 0;
2861 err = _pjsua.thread_register("python worker", thread_desc)
2862 _lib._err_check("thread_register()", _lib, err)
Benny Prijono55040452008-07-21 18:20:57 +00002863 while _lib and _lib._quit == 0:
Benny Prijono6ecef072008-07-21 22:46:35 +00002864 _lib.handle_events(1)
2865 time.sleep(0.050)
Benny Prijono55040452008-07-21 18:20:57 +00002866 if _lib:
2867 _lib._quit = 2
Benny Prijono6ecef072008-07-21 22:46:35 +00002868 _Trace(('worker thread exited..',))
Benny Prijono9c461142008-07-10 22:41:20 +00002869
Benny Prijono55040452008-07-21 18:20:57 +00002870def _Trace(args):
2871 if True:
2872 print "** ",
2873 for arg in args:
2874 print arg,
2875 print " **"
Benny Prijono6ecef072008-07-21 22:46:35 +00002876