blob: 0eea110f91876a8cb1f9cdcd88182b172e892fce [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 Prijono9c461142008-07-10 22:41:20 +0000155
156class Error:
Benny Prijonob85ba652008-07-11 00:55:22 +0000157 """Error exception class.
158
159 Member documentation:
160
161 op_name -- name of the operation that generated this error.
162 obj -- the object that generated this error.
163 err_code -- the error code.
164
165 """
Benny Prijono9c461142008-07-10 22:41:20 +0000166 op_name = ""
167 obj = None
168 err_code = -1
169 _err_msg = ""
170
171 def __init__(self, op_name, obj, err_code, err_msg=""):
172 self.op_name = op_name
173 self.obj = obj
174 self.err_code = err_code
175 self._err_msg = err_msg
176
177 def err_msg(self):
178 "Retrieve the description of the error."
179 if self._err_msg != "":
180 return self._err_msg
181 self._err_msg = Lib.strerror(self.err_code)
182 return self._err_msg
183
184 def __str__(self):
185 return "Object: " + str(self.obj) + ", operation=" + self.op_name + \
186 ", error=" + self.err_msg()
187
188#
189# Constants
190#
191
192class TransportType:
Benny Prijonob85ba652008-07-11 00:55:22 +0000193 """SIP transport type constants.
194
195 Member documentation:
196 UNSPECIFIED -- transport type is unknown or unspecified
197 UDP -- UDP transport
198 TCP -- TCP transport
199 TLS -- TLS transport
200 IPV6 -- this is not a transport type but rather a flag
201 to select the IPv6 version of a transport
202 UDP_IPV6 -- IPv6 UDP transport
203 TCP_IPV6 -- IPv6 TCP transport
204 """
Benny Prijono9c461142008-07-10 22:41:20 +0000205 UNSPECIFIED = 0
206 UDP = 1
207 TCP = 2
208 TLS = 3
209 IPV6 = 128
210 UDP_IPV6 = UDP + IPV6
211 TCP_IPV6 = TCP + IPV6
212
213class TransportFlag:
Benny Prijonob85ba652008-07-11 00:55:22 +0000214 """Transport flags to indicate the characteristics of the transport.
215
216 Member documentation:
217
218 RELIABLE -- transport is reliable.
219 SECURE -- transport is secure.
220 DATAGRAM -- transport is datagram based.
221
222 """
Benny Prijono9c461142008-07-10 22:41:20 +0000223 RELIABLE = 1
224 SECURE = 2
225 DATAGRAM = 4
226
227class CallRole:
Benny Prijonob85ba652008-07-11 00:55:22 +0000228 """Call role constants.
229
230 Member documentation:
231
232 CALLER -- role is caller
233 CALLEE -- role is callee
234
235 """
Benny Prijono9c461142008-07-10 22:41:20 +0000236 CALLER = 0
237 CALLEE = 1
238
239class CallState:
Benny Prijonob85ba652008-07-11 00:55:22 +0000240 """Call state constants.
241
242 Member documentation:
243
244 NULL -- call is not initialized.
245 CALLING -- initial INVITE is sent.
246 INCOMING -- initial INVITE is received.
247 EARLY -- provisional response has been sent or received.
248 CONNECTING -- 200/OK response has been sent or received.
249 CONFIRMED -- ACK has been sent or received.
250 DISCONNECTED -- call is disconnected.
251 """
Benny Prijono9c461142008-07-10 22:41:20 +0000252 NULL = 0
253 CALLING = 1
254 INCOMING = 2
255 EARLY = 3
256 CONNECTING = 4
257 CONFIRMED = 5
258 DISCONNECTED = 6
259
260
261class MediaState:
Benny Prijonob85ba652008-07-11 00:55:22 +0000262 """Call media state constants.
263
264 Member documentation:
265
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000266 NULL -- media is not available.
Benny Prijonob85ba652008-07-11 00:55:22 +0000267 ACTIVE -- media is active.
268 LOCAL_HOLD -- media is put on-hold by local party.
269 REMOTE_HOLD -- media is put on-hold by remote party.
270 ERROR -- media error (e.g. ICE negotiation failure).
271 """
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000272 NULL = 0
Benny Prijono9c461142008-07-10 22:41:20 +0000273 ACTIVE = 1
274 LOCAL_HOLD = 2
275 REMOTE_HOLD = 3
276 ERROR = 4
277
278
279class MediaDir:
Benny Prijonob85ba652008-07-11 00:55:22 +0000280 """Media direction constants.
281
282 Member documentation:
283
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000284 NULL -- media is not active
Benny Prijonob85ba652008-07-11 00:55:22 +0000285 ENCODING -- media is active in transmit/encoding direction only.
286 DECODING -- media is active in receive/decoding direction only
287 ENCODING_DECODING -- media is active in both directions.
288 """
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000289 NULL = 0
Benny Prijono9c461142008-07-10 22:41:20 +0000290 ENCODING = 1
291 DECODING = 2
292 ENCODING_DECODING = 3
293
294
295class PresenceActivity:
Benny Prijonob85ba652008-07-11 00:55:22 +0000296 """Presence activities constants.
297
298 Member documentation:
299
300 UNKNOWN -- the person activity is unknown
301 AWAY -- the person is currently away
302 BUSY -- the person is currently engaging in other activity
303 """
Benny Prijono9c461142008-07-10 22:41:20 +0000304 UNKNOWN = 0
305 AWAY = 1
306 BUSY = 2
307
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000308
309class SubscriptionState:
310 """Presence subscription state constants.
311
312 """
313 NULL = 0
314 SENT = 1
315 ACCEPTED = 2
316 PENDING = 3
317 ACTIVE = 4
318 TERMINATED = 5
319 UNKNOWN = 6
320
321
Benny Prijono9c461142008-07-10 22:41:20 +0000322class TURNConnType:
Benny Prijonob85ba652008-07-11 00:55:22 +0000323 """These constants specifies the connection type to TURN server.
324
325 Member documentation:
326 UDP -- use UDP transport.
327 TCP -- use TCP transport.
328 TLS -- use TLS transport.
329 """
Benny Prijono9c461142008-07-10 22:41:20 +0000330 UDP = 17
331 TCP = 6
332 TLS = 255
333
334
335class UAConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000336 """User agent configuration to be specified in Lib.init().
337
338 Member documentation:
339
340 max_calls -- maximum number of calls to be supported.
Benny Prijono288d4bd2008-07-19 15:40:21 +0000341 nameserver -- list of nameserver hostnames or IP addresses. Nameserver
Benny Prijonob85ba652008-07-11 00:55:22 +0000342 must be configured if DNS SRV resolution is desired.
343 stun_domain -- if nameserver is configured, this can be used to query
344 the STUN server with DNS SRV.
345 stun_host -- the hostname or IP address of the STUN server. This will
346 also be used if DNS SRV resolution for stun_domain fails.
347 user_agent -- Optionally specify the user agent name.
348 """
Benny Prijono9c461142008-07-10 22:41:20 +0000349 max_calls = 4
350 nameserver = []
351 stun_domain = ""
352 stun_host = ""
353 user_agent = "pjsip python"
354
355 def _cvt_from_pjsua(self, cfg):
356 self.max_calls = cfg.max_calls
357 self.thread_cnt = cfg.thread_cnt
358 self.nameserver = cfg.nameserver
359 self.stun_domain = cfg.stun_domain
360 self.stun_host = cfg.stun_host
361 self.user_agent = cfg.user_agent
362
363 def _cvt_to_pjsua(self):
364 cfg = _pjsua.config_default()
365 cfg.max_calls = self.max_calls
366 cfg.thread_cnt = 0
367 cfg.nameserver = self.nameserver
368 cfg.stun_domain = self.stun_domain
369 cfg.stun_host = self.stun_host
370 cfg.user_agent = self.user_agent
371 return cfg
372
373
374class LogConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000375 """Logging configuration to be specified in Lib.init().
376
377 Member documentation:
378
379 msg_logging -- specify if SIP messages should be logged. Set to
380 True.
381 level -- specify the input verbosity level.
382 console_level -- specify the output verbosity level.
383 decor -- specify log decoration.
384 filename -- specify the log filename.
385 callback -- specify callback to be called to write the logging
386 messages. Sample function:
387
388 def log_cb(level, str, len):
389 print str,
390
391 """
Benny Prijono9c461142008-07-10 22:41:20 +0000392 msg_logging = True
393 level = 5
394 console_level = 5
395 decor = 0
396 filename = ""
397 callback = None
398
399 def __init__(self, level=-1, filename="", callback=None,
400 console_level=-1):
401 self._cvt_from_pjsua(_pjsua.logging_config_default())
402 if level != -1:
403 self.level = level
404 if filename != "":
405 self.filename = filename
406 if callback != None:
407 self.callback = callback
408 if console_level != -1:
409 self.console_level = console_level
410
411 def _cvt_from_pjsua(self, cfg):
412 self.msg_logging = cfg.msg_logging
413 self.level = cfg.level
414 self.console_level = cfg.console_level
415 self.decor = cfg.decor
416 self.filename = cfg.log_filename
417 self.callback = cfg.cb
418
419 def _cvt_to_pjsua(self):
420 cfg = _pjsua.logging_config_default()
421 cfg.msg_logging = self.msg_logging
422 cfg.level = self.level
423 cfg.console_level = self.console_level
424 cfg.decor = self.decor
425 cfg.log_filename = self.filename
426 cfg.cb = self.callback
427 return cfg
428
429
430class MediaConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000431 """Media configuration to be specified in Lib.init().
432
433 Member documentation:
434
435 clock_rate -- specify the core clock rate of the audio,
436 most notably the conference bridge.
437 snd_clock_rate -- optionally specify different clock rate for
438 the sound device.
439 snd_auto_close_time -- specify the duration in seconds when the
440 sound device should be closed after inactivity
441 period.
442 channel_count -- specify the number of channels to open the sound
443 device and the conference bridge.
444 audio_frame_ptime -- specify the length of audio frames in millisecond.
445 max_media_ports -- specify maximum number of audio ports to be
446 supported by the conference bridge.
447 quality -- specify the audio quality setting (1-10)
448 ptime -- specify the audio packet length of transmitted
449 RTP packet.
450 no_vad -- disable Voice Activity Detector (VAD) or Silence
451 Detector (SD)
452 ilbc_mode -- specify iLBC codec mode (must be 30 for now)
453 tx_drop_pct -- randomly drop transmitted RTP packets (for
454 simulation). Number is in percent.
455 rx_drop_pct -- randomly drop received RTP packets (for
456 simulation). Number is in percent.
457 ec_options -- Echo Canceller option (specify zero).
458 ec_tail_len -- specify Echo Canceller tail length in milliseconds.
459 Value zero will disable the echo canceller.
460 jb_min -- specify the minimum jitter buffer size in
461 milliseconds. Put -1 for default.
462 jb_max -- specify the maximum jitter buffer size in
463 milliseconds. Put -1 for default.
464 enable_ice -- enable Interactive Connectivity Establishment (ICE)
465 enable_turn -- enable TURN relay. TURN server settings must also
466 be configured.
467 turn_server -- specify the domain or hostname or IP address of
468 the TURN server, in "host[:port]" format.
469 turn_conn_type -- specify connection type to the TURN server, from
470 the TURNConnType constant.
471 turn_cred -- specify AuthCred for the TURN credential.
472 """
Benny Prijono9c461142008-07-10 22:41:20 +0000473 clock_rate = 16000
474 snd_clock_rate = 0
475 snd_auto_close_time = 5
476 channel_count = 1
477 audio_frame_ptime = 20
478 max_media_ports = 32
479 quality = 6
480 ptime = 0
481 no_vad = False
482 ilbc_mode = 30
483 tx_drop_pct = 0
484 rx_drop_pct = 0
485 ec_options = 0
486 ec_tail_len = 256
487 jb_min = -1
488 jb_max = -1
489 enable_ice = True
490 enable_turn = False
491 turn_server = ""
492 turn_conn_type = TURNConnType.UDP
493 turn_cred = None
494
495 def __init__(self):
496 default = _pjsua.media_config_default()
497 self._cvt_from_pjsua(default)
498
499 def _cvt_from_pjsua(self, cfg):
500 self.clock_rate = cfg.clock_rate
501 self.snd_clock_rate = cfg.snd_clock_rate
502 self.snd_auto_close_time = cfg.snd_auto_close_time
503 self.channel_count = cfg.channel_count
504 self.audio_frame_ptime = cfg.audio_frame_ptime
505 self.max_media_ports = cfg.max_media_ports
506 self.quality = cfg.quality
507 self.ptime = cfg.ptime
508 self.no_vad = cfg.no_vad
509 self.ilbc_mode = cfg.ilbc_mode
510 self.tx_drop_pct = cfg.tx_drop_pct
511 self.rx_drop_pct = cfg.rx_drop_pct
512 self.ec_options = cfg.ec_options
513 self.ec_tail_len = cfg.ec_tail_len
514 self.jb_min = cfg.jb_min
515 self.jb_max = cfg.jb_max
516 self.enable_ice = cfg.enable_ice
517 self.enable_turn = cfg.enable_turn
518 self.turn_server = cfg.turn_server
519 self.turn_conn_type = cfg.turn_conn_type
520 if cfg.turn_username:
521 self.turn_cred = AuthCred(cfg.turn_realm, cfg.turn_username,
522 cfg.turn_passwd, cfg.turn_passwd_type)
523 else:
524 self.turn_cred = None
525
526 def _cvt_to_pjsua(self):
527 cfg = _pjsua.media_config_default()
528 cfg.clock_rate = self.clock_rate
529 cfg.snd_clock_rate = self.snd_clock_rate
530 cfg.snd_auto_close_time = self.snd_auto_close_time
531 cfg.channel_count = self.channel_count
532 cfg.audio_frame_ptime = self.audio_frame_ptime
533 cfg.max_media_ports = self.max_media_ports
534 cfg.quality = self.quality
535 cfg.ptime = self.ptime
536 cfg.no_vad = self.no_vad
537 cfg.ilbc_mode = self.ilbc_mode
538 cfg.tx_drop_pct = self.tx_drop_pct
539 cfg.rx_drop_pct = self.rx_drop_pct
540 cfg.ec_options = self.ec_options
541 cfg.ec_tail_len = self.ec_tail_len
542 cfg.jb_min = self.jb_min
543 cfg.jb_max = self.jb_max
544 cfg.enable_ice = self.enable_ice
545 cfg.enable_turn = self.enable_turn
546 cfg.turn_server = self.turn_server
547 cfg.turn_conn_type = self.turn_conn_type
548 if self.turn_cred:
549 cfg.turn_realm = self.turn_cred.realm
550 cfg.turn_username = self.turn_cred.username
551 cfg.turn_passwd_type = self.turn_cred.passwd_type
552 cfg.turn_passwd = self.turn_cred.passwd
553 return cfg
554
555
556class TransportConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000557 """SIP transport configuration class.
558
559 Member configuration:
560
561 port -- port number.
562 bound_addr -- optionally specify the address to bind the socket to.
563 Default is empty to bind to INADDR_ANY.
564 public_addr -- optionally override the published address for this
565 transport. If empty, the default behavior is to get
566 the public address from STUN or from the selected
567 local interface. Format is "host:port".
568 """
Benny Prijono9c461142008-07-10 22:41:20 +0000569 port = 0
570 bound_addr = ""
571 public_addr = ""
572
573 def __init__(self, port=5060,
574 bound_addr="", public_addr=""):
575 self.port = port
576 self.bound_addr = bound_addr
577 self.public_addr = public_addr
578
579 def _cvt_to_pjsua(self):
580 cfg = _pjsua.transport_config_default()
581 cfg.port = self.port
582 cfg.bound_addr = self.bound_addr
583 cfg.public_addr = self.public_addr
584 return cfg
585
586
587class TransportInfo:
588 """SIP transport info.
Benny Prijonob85ba652008-07-11 00:55:22 +0000589
590 Member documentation:
591
592 type -- transport type, from TransportType constants.
593 description -- longer description for this transport.
594 is_reliable -- True if transport is reliable.
595 is_secure -- True if transport is secure.
596 is_datagram -- True if transport is datagram based.
597 host -- the IP address of this transport.
598 port -- the port number.
599 ref_cnt -- number of objects referencing this transport.
Benny Prijono9c461142008-07-10 22:41:20 +0000600 """
601 type = ""
602 description = ""
603 is_reliable = False
604 is_secure = False
605 is_datagram = False
606 host = ""
607 port = 0
608 ref_cnt = 0
609
610 def __init__(self, ti):
611 self.type = ti.type_name
612 self.description = ti.info
613 self.is_reliable = (ti.flag & TransportFlag.RELIABLE)
614 self.is_secure = (ti.flag & TransportFlag.SECURE)
615 self.is_datagram = (ti.flag & TransportFlag.DATAGRAM)
616 self.host = ti.addr
617 self.port = ti.port
618 self.ref_cnt = ti.usage_count
619
620
621class Transport:
622 "SIP transport class."
623 _id = -1
624 _lib = None
625 _obj_name = ""
626
627 def __init__(self, lib, id):
Benny Prijono55040452008-07-21 18:20:57 +0000628 self._lib = weakref.proxy(lib)
Benny Prijono9c461142008-07-10 22:41:20 +0000629 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +0000630 self._obj_name = "{Transport " + self.info().description + "}"
631 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +0000632
Benny Prijono55040452008-07-21 18:20:57 +0000633 def __del__(self):
634 _Trace((self, 'destroyed'))
635
Benny Prijono9c461142008-07-10 22:41:20 +0000636 def __str__(self):
637 return self._obj_name
638
639 def info(self):
640 """Get TransportInfo.
641 """
Benny Prijono55040452008-07-21 18:20:57 +0000642 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000643 ti = _pjsua.transport_get_info(self._id)
644 if not ti:
645 self._lib._err_check("info()", self, -1, "Invalid transport")
646 return TransportInfo(ti)
647
648 def enable(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000649 """Enable this transport."""
Benny Prijono55040452008-07-21 18:20:57 +0000650 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000651 err = _pjsua.transport_set_enable(self._id, True)
652 self._lib._err_check("enable()", self, err)
653
654 def disable(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000655 """Disable this transport."""
Benny Prijono55040452008-07-21 18:20:57 +0000656 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000657 err = _pjsua.transport_set_enable(self._id, 0)
658 self._lib._err_check("disable()", self, err)
659
660 def close(self, force=False):
Benny Prijonob85ba652008-07-11 00:55:22 +0000661 """Close and destroy this transport.
662
663 Keyword argument:
664 force -- force deletion of this transport (not recommended).
665 """
Benny Prijono55040452008-07-21 18:20:57 +0000666 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000667 err = _pjsua.transport_close(self._id, force)
668 self._lib._err_check("close()", self, err)
669
670
671class SIPUri:
Benny Prijonob85ba652008-07-11 00:55:22 +0000672 """Helper class to parse the most important components of SIP URI.
673
674 Member documentation:
675
676 scheme -- URI scheme ("sip" or "sips")
677 user -- user part of the URI (may be empty)
678 host -- host name part
679 port -- optional port number (zero if port is not specified).
680 transport -- transport parameter, or empty if transport is not
681 specified.
682
683 """
Benny Prijono9c461142008-07-10 22:41:20 +0000684 scheme = ""
685 user = ""
686 host = ""
687 port = 0
688 transport = ""
689
Benny Prijonob85ba652008-07-11 00:55:22 +0000690 def __init__(self, uri=None):
691 if uri:
692 self.decode(uri)
Benny Prijono9c461142008-07-10 22:41:20 +0000693
694 def decode(self, uri):
Benny Prijonob85ba652008-07-11 00:55:22 +0000695 """Parse SIP URL.
696
697 Keyword argument:
698 uri -- the URI string.
699
700 """
Benny Prijono9c461142008-07-10 22:41:20 +0000701 self.scheme, self.user, self.host, self.port, self.transport = \
702 _pjsua.parse_simple_uri(uri)
703
704 def encode(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000705 """Encode this object into SIP URI string.
706
707 Return:
708 URI string.
709
710 """
Benny Prijono9c461142008-07-10 22:41:20 +0000711 output = self.scheme + ":"
712 if self.user and len(self.user):
713 output = output + self.user + "@"
714 output = output + self.host
715 if self.port:
716 output = output + ":" + output(self.port)
717 if self.transport:
718 output = output + ";transport=" + self.transport
719 return output
720
Benny Prijonob85ba652008-07-11 00:55:22 +0000721
Benny Prijono9c461142008-07-10 22:41:20 +0000722class AuthCred:
Benny Prijonob85ba652008-07-11 00:55:22 +0000723 """Authentication credential for SIP or TURN account.
724
725 Member documentation:
726
727 scheme -- authentication scheme (default is "Digest")
728 realm -- realm
729 username -- username
730 passwd_type -- password encoding (zero for plain-text)
731 passwd -- the password
732 """
Benny Prijono9c461142008-07-10 22:41:20 +0000733 scheme = "Digest"
734 realm = "*"
735 username = ""
736 passwd_type = 0
737 passwd = ""
738
739 def __init__(self, realm, username, passwd, scheme="Digest", passwd_type=0):
740 self.scheme = scheme
741 self.realm = realm
742 self.username = username
743 self.passwd_type = passwd_type
744 self.passwd = passwd
745
746
747class AccountConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000748 """ This describes account configuration to create an account.
749
750 Member documentation:
751
752 priority -- account priority for matching incoming
753 messages.
754 id -- SIP URI of this account. This setting is
755 mandatory.
756 force_contact -- force to use this URI as Contact URI. Setting
757 this value is generally not recommended.
758 reg_uri -- specify the registrar URI. Mandatory if
759 registration is required.
760 reg_timeout -- specify the SIP registration refresh interval
761 in seconds.
762 require_100rel -- specify if reliable provisional response is
763 to be enforced (with Require header).
764 publish_enabled -- specify if PUBLISH should be used. When
765 enabled, the PUBLISH will be sent to the
766 registrar.
767 pidf_tuple_id -- optionally specify the tuple ID in outgoing
768 PIDF document.
769 proxy -- list of proxy URI.
770 auth_cred -- list of AuthCred containing credentials to
771 authenticate against the registrars and
772 the proxies.
773 auth_initial_send -- specify if empty Authorization header should be
774 sent. May be needed for IMS.
775 auth_initial_algorithm -- when auth_initial_send is enabled, optionally
776 specify the authentication algorithm to use.
777 Valid values are "md5", "akav1-md5", or
778 "akav2-md5".
779 transport_id -- optionally specify the transport ID to be used
780 by this account. Shouldn't be needed unless
781 for specific requirements (e.g. in multi-homed
782 scenario).
783 allow_contact_rewrite -- specify whether the account should learn its
784 Contact address from REGISTER response and
785 update the registration accordingly. Default is
786 True.
787 ka_interval -- specify the interval to send NAT keep-alive
788 packet.
789 ka_data -- specify the NAT keep-alive packet contents.
790 use_srtp -- specify the SRTP usage policy. Valid values
791 are: 0=disable, 1=optional, 2=mandatory.
792 Default is 0.
793 srtp_secure_signaling -- specify the signaling security level required
794 by SRTP. Valid values are: 0=no secure
795 transport is required, 1=hop-by-hop secure
796 transport such as TLS is required, 2=end-to-
797 end secure transport is required (i.e. "sips").
Benny Prijono9c461142008-07-10 22:41:20 +0000798 """
799 priority = 0
800 id = ""
801 force_contact = ""
802 reg_uri = ""
803 reg_timeout = 0
804 require_100rel = False
805 publish_enabled = False
806 pidf_tuple_id = ""
807 proxy = []
808 auth_cred = []
809 auth_initial_send = False
810 auth_initial_algorithm = ""
811 transport_id = -1
812 allow_contact_rewrite = True
813 ka_interval = 15
814 ka_data = "\r\n"
815 use_srtp = 0
816 srtp_secure_signaling = 1
817
818 def __init__(self, domain="", username="", password="",
819 display="", registrar="", proxy=""):
820 """
821 Construct account config. If domain argument is specified,
822 a typical configuration will be built.
823
824 Keyword arguments:
825 domain -- domain name of the server.
826 username -- user name.
827 password -- plain-text password.
828 display -- optional display name for the user name.
829 registrar -- the registrar URI. If domain name is specified
830 and this argument is empty, the registrar URI
831 will be constructed from the domain name.
832 proxy -- the proxy URI. If domain name is specified
833 and this argument is empty, the proxy URI
834 will be constructed from the domain name.
835
836 """
837 default = _pjsua.acc_config_default()
838 self._cvt_from_pjsua(default)
839 if domain!="":
840 self.build_config(domain, username, password,
841 display, registrar, proxy)
842
843 def build_config(self, domain, username, password, display="",
844 registrar="", proxy=""):
845 """
846 Construct account config. If domain argument is specified,
847 a typical configuration will be built.
848
849 Keyword arguments:
850 domain -- domain name of the server.
851 username -- user name.
852 password -- plain-text password.
853 display -- optional display name for the user name.
854 registrar -- the registrar URI. If domain name is specified
855 and this argument is empty, the registrar URI
856 will be constructed from the domain name.
857 proxy -- the proxy URI. If domain name is specified
858 and this argument is empty, the proxy URI
859 will be constructed from the domain name.
860
861 """
862 if display != "":
863 display = display + " "
864 userpart = username
865 if userpart != "":
866 userpart = userpart + "@"
867 self.id = display + "<sip:" + userpart + domain + ">"
868 self.reg_uri = registrar
869 if self.reg_uri == "":
870 self.reg_uri = "sip:" + domain
871 if proxy == "":
872 proxy = "sip:" + domain + ";lr"
873 if proxy.find(";lr") == -1:
874 proxy = proxy + ";lr"
875 self.proxy.append(proxy)
876 if username != "":
877 self.auth_cred.append(AuthCred("*", username, password))
878
879 def _cvt_from_pjsua(self, cfg):
880 self.priority = cfg.priority
881 self.id = cfg.id
882 self.force_contact = cfg.force_contact
883 self.reg_uri = cfg.reg_uri
884 self.reg_timeout = cfg.reg_timeout
885 self.require_100rel = cfg.require_100rel
886 self.publish_enabled = cfg.publish_enabled
887 self.pidf_tuple_id = cfg.pidf_tuple_id
888 self.proxy = cfg.proxy
889 for cred in cfg.cred_info:
890 self.auth_cred.append(AuthCred(cred.realm, cred.username,
891 cred.data, cred.scheme,
892 cred.data_type))
893 self.auth_initial_send = cfg.auth_initial_send
894 self.auth_initial_algorithm = cfg.auth_initial_algorithm
895 self.transport_id = cfg.transport_id
896 self.allow_contact_rewrite = cfg.allow_contact_rewrite
897 self.ka_interval = cfg.ka_interval
898 self.ka_data = cfg.ka_data
899 self.use_srtp = cfg.use_srtp
900 self.srtp_secure_signaling = cfg.srtp_secure_signaling
901
902 def _cvt_to_pjsua(self):
903 cfg = _pjsua.acc_config_default()
904 cfg.priority = self.priority
905 cfg.id = self.id
906 cfg.force_contact = self.force_contact
907 cfg.reg_uri = self.reg_uri
908 cfg.reg_timeout = self.reg_timeout
909 cfg.require_100rel = self.require_100rel
910 cfg.publish_enabled = self.publish_enabled
911 cfg.pidf_tuple_id = self.pidf_tuple_id
912 cfg.proxy = self.proxy
913 for cred in self.auth_cred:
914 c = _pjsua.Pjsip_Cred_Info()
915 c.realm = cred.realm
916 c.scheme = cred.scheme
917 c.username = cred.username
918 c.data_type = cred.passwd_type
919 c.data = cred.passwd
920 cfg.cred_info.append(c)
921 cfg.auth_initial_send = self.auth_initial_send
922 cfg.auth_initial_algorithm = self.auth_initial_algorithm
923 cfg.transport_id = self.transport_id
924 cfg.allow_contact_rewrite = self.allow_contact_rewrite
925 cfg.ka_interval = self.ka_interval
926 cfg.ka_data = self.ka_data
927 cfg.use_srtp = self.use_srtp
928 cfg.srtp_secure_signaling = self.srtp_secure_signaling
929 return cfg
930
931
932# Account information
933class AccountInfo:
934 """This describes Account info. Application retrives account info
935 with Account.info().
936
Benny Prijonob85ba652008-07-11 00:55:22 +0000937 Member documentation:
938
939 is_default -- True if this is the default account.
940 uri -- the account URI.
941 reg_active -- True if registration is active for this account.
942 reg_expires -- contains the current registration expiration value,
943 in seconds.
944 reg_status -- the registration status. If the value is less than
945 700, it specifies SIP status code. Value greater than
946 this specifies the error code.
947 reg_reason -- contains the registration status text (e.g. the
948 error message).
949 online_status -- the account's presence online status, True if it's
950 publishing itself as online.
951 online_text -- the account's presence status text.
952
Benny Prijono9c461142008-07-10 22:41:20 +0000953 """
954 is_default = False
955 uri = ""
956 reg_active = False
957 reg_expires = -1
958 reg_status = 0
959 reg_reason = ""
960 online_status = False
961 online_text = ""
962
963 def __init__(self, ai):
964 self.is_default = ai.is_default
965 self.uri = ai.acc_uri
966 self.reg_active = ai.has_registration
967 self.reg_expires = ai.expires
968 self.reg_status = ai.status
969 self.reg_reason = ai.status_text
970 self.online_status = ai.online_status
971 self.online_text = ai.online_status_text
972
973# Account callback
974class AccountCallback:
975 """Class to receive notifications on account's events.
976
977 Derive a class from this class and register it to the Account object
978 using Account.set_callback() to start receiving events from the Account
979 object.
Benny Prijonob85ba652008-07-11 00:55:22 +0000980
981 Member documentation:
982
983 account -- the Account object.
984
Benny Prijono9c461142008-07-10 22:41:20 +0000985 """
986 account = None
987
Benny Prijono55040452008-07-21 18:20:57 +0000988 def __init__(self, account=None):
989 self._set_account(account)
990
991 def __del__(self):
992 pass
993
994 def _set_account(self, account):
995 if account:
996 self.account = weakref.proxy(account)
997 else:
998 self.account = None
Benny Prijono9c461142008-07-10 22:41:20 +0000999
1000 def on_reg_state(self):
1001 """Notification that the registration status has changed.
1002 """
1003 pass
1004
1005 def on_incoming_call(self, call):
1006 """Notification about incoming call.
1007
1008 Unless this callback is implemented, the default behavior is to
1009 reject the call with default status code.
1010
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001011 Keyword arguments:
1012 call -- the new incoming call
Benny Prijono9c461142008-07-10 22:41:20 +00001013 """
1014 call.hangup()
1015
Benny Prijono55040452008-07-21 18:20:57 +00001016 def on_incoming_subscribe(self, buddy, from_uri, contact_uri, pres_obj):
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001017 """Notification when incoming SUBSCRIBE request is received.
1018
1019 Application may use this callback to authorize the incoming
1020 subscribe request (e.g. ask user permission if the request
1021 should be granted)
1022
1023 Keyword arguments:
1024 buddy -- The buddy object, if buddy is found. Otherwise
1025 the value is None.
1026 from_uri -- The URI string of the sender.
1027 pres_obj -- Opaque presence subscription object, which is
1028 needed by Account.pres_notify()
1029
1030 Return:
1031 Tuple (code, reason), where:
1032 code: The status code. If code is >= 300, the
1033 request is rejected. If code is 200, the
1034 request is accepted and NOTIFY will be sent
1035 automatically. If code is 202, application
1036 must accept or reject the request later with
1037 Account.press_notify().
1038 reason: Optional reason phrase, or None to use the
1039 default reasoh phrase for the status code.
1040 """
1041 return (200, None)
1042
Benny Prijono9c461142008-07-10 22:41:20 +00001043 def on_pager(self, from_uri, contact, mime_type, body):
1044 """
1045 Notification that incoming instant message is received on
1046 this account.
1047
1048 Keyword arguments:
1049 from_uri -- sender's URI
1050 contact -- sender's Contact URI
1051 mime_type -- MIME type of the instant message body
1052 body -- the instant message body
1053
1054 """
1055 pass
1056
1057 def on_pager_status(self, to_uri, body, im_id, code, reason):
1058 """
1059 Notification about the delivery status of previously sent
1060 instant message.
1061
1062 Keyword arguments:
1063 to_uri -- the destination URI of the message
1064 body -- the message body
1065 im_id -- message ID
1066 code -- SIP status code
1067 reason -- SIP reason phrase
1068
1069 """
1070 pass
1071
1072 def on_typing(self, from_uri, contact, is_typing):
1073 """
1074 Notification that remote is typing or stop typing.
1075
1076 Keyword arguments:
1077 buddy -- Buddy object for the sender, if found. Otherwise
1078 this will be None
1079 from_uri -- sender's URI of the indication
1080 contact -- sender's contact URI
1081 is_typing -- boolean to indicate whether remote is currently
1082 typing an instant message.
1083
1084 """
1085 pass
1086
1087
1088
1089class Account:
1090 """This describes SIP account class.
1091
1092 PJSUA accounts provide identity (or identities) of the user who is
1093 currently using the application. In SIP terms, the identity is used
1094 as the From header in outgoing requests.
1095
1096 Account may or may not have client registration associated with it.
1097 An account is also associated with route set and some authentication
1098 credentials, which are used when sending SIP request messages using
1099 the account. An account also has presence's online status, which
1100 will be reported to remote peer when they subscribe to the account's
1101 presence, or which is published to a presence server if presence
1102 publication is enabled for the account.
1103
1104 Account is created with Lib.create_account(). At least one account
1105 MUST be created. If no user association is required, application can
1106 create a userless account by calling Lib.create_account_for_transport().
1107 A userless account identifies local endpoint instead of a particular
1108 user, and it correspond with a particular transport instance.
1109
1110 Also one account must be set as the default account, which is used as
1111 the account to use when PJSUA fails to match a request with any other
1112 accounts.
1113
1114 """
1115 _id = -1
1116 _lib = None
1117 _cb = AccountCallback(None)
1118 _obj_name = ""
1119
Benny Prijono55040452008-07-21 18:20:57 +00001120 def __init__(self, lib, id, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001121 """Construct this class. This is normally called by Lib class and
1122 not by application.
1123
1124 Keyword arguments:
1125 lib -- the Lib instance.
1126 id -- the pjsua account ID.
Benny Prijono55040452008-07-21 18:20:57 +00001127 cb -- AccountCallback instance to receive events from this Account.
1128 If callback is not specified here, it must be set later
1129 using set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001130 """
Benny Prijono9c461142008-07-10 22:41:20 +00001131 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +00001132 self._lib = weakref.ref(lib)
1133 self._obj_name = "{Account " + self.info().uri + "}"
1134 self.set_callback(cb)
1135 _pjsua.acc_set_user_data(self._id, self)
1136 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001137
1138 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001139 if self._id != -1:
1140 _pjsua.acc_set_user_data(self._id, 0)
1141 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001142
1143 def __str__(self):
1144 return self._obj_name
1145
1146 def info(self):
1147 """Retrieve AccountInfo for this account.
1148 """
Benny Prijono55040452008-07-21 18:20:57 +00001149 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001150 ai = _pjsua.acc_get_info(self._id)
1151 if ai==None:
Benny Prijono55040452008-07-21 18:20:57 +00001152 self._lib()._err_check("info()", self, -1, "Invalid account")
Benny Prijono9c461142008-07-10 22:41:20 +00001153 return AccountInfo(ai)
1154
1155 def is_valid(self):
1156 """
1157 Check if this account is still valid.
1158
1159 """
Benny Prijono55040452008-07-21 18:20:57 +00001160 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001161 return _pjsua.acc_is_valid(self._id)
1162
1163 def set_callback(self, cb):
1164 """Register callback to receive notifications from this object.
1165
1166 Keyword argument:
1167 cb -- AccountCallback instance.
1168
1169 """
1170 if cb:
1171 self._cb = cb
1172 else:
1173 self._cb = AccountCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001174 self._cb._set_account(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001175
1176 def set_default(self):
1177 """ Set this account as default account to send outgoing requests
1178 and as the account to receive incoming requests when more exact
1179 matching criteria fails.
1180 """
Benny Prijono55040452008-07-21 18:20:57 +00001181 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001182 err = _pjsua.acc_set_default(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001183 self._lib()._err_check("set_default()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001184
1185 def is_default(self):
1186 """ Check if this account is the default account.
1187
1188 """
Benny Prijono55040452008-07-21 18:20:57 +00001189 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001190 def_id = _pjsua.acc_get_default()
1191 return self.is_valid() and def_id==self._id
1192
1193 def delete(self):
1194 """ Delete this account.
1195
1196 """
Benny Prijono55040452008-07-21 18:20:57 +00001197 lck = self._lib().auto_lock()
1198 err = _pjsua.acc_set_user_data(self._id, 0)
1199 self._lib()._err_check("delete()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001200 err = _pjsua.acc_del(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001201 self._lib()._err_check("delete()", self, err)
1202 self._id = -1
Benny Prijono9c461142008-07-10 22:41:20 +00001203
1204 def set_basic_status(self, is_online):
1205 """ Set basic presence status of this account.
1206
1207 Keyword argument:
1208 is_online -- boolean to indicate basic presence availability.
1209
1210 """
Benny Prijono55040452008-07-21 18:20:57 +00001211 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001212 err = _pjsua.acc_set_online_status(self._id, is_online)
Benny Prijono55040452008-07-21 18:20:57 +00001213 self._lib()._err_check("set_basic_status()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001214
1215 def set_presence_status(self, is_online,
1216 activity=PresenceActivity.UNKNOWN,
1217 pres_text="", rpid_id=""):
1218 """ Set presence status of this account.
1219
1220 Keyword arguments:
1221 is_online -- boolean to indicate basic presence availability
1222 activity -- value from PresenceActivity
1223 pres_text -- optional string to convey additional information about
1224 the activity (such as "On the phone")
1225 rpid_id -- optional string to be placed as RPID ID.
1226
1227 """
Benny Prijono55040452008-07-21 18:20:57 +00001228 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001229 err = _pjsua.acc_set_online_status2(self._id, is_online, activity,
1230 pres_text, rpid_id)
Benny Prijono55040452008-07-21 18:20:57 +00001231 self._lib()._err_check("set_presence_status()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001232
1233 def set_registration(self, renew):
1234 """Manually renew registration or unregister from the server.
1235
1236 Keyword argument:
1237 renew -- boolean to indicate whether registration is renewed.
1238 Setting this value for False will trigger unregistration.
1239
1240 """
Benny Prijono55040452008-07-21 18:20:57 +00001241 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001242 err = _pjsua.acc_set_registration(self._id, renew)
Benny Prijono55040452008-07-21 18:20:57 +00001243 self._lib()._err_check("set_registration()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001244
1245 def set_transport(self, transport):
1246 """Set this account to only use the specified transport to send
1247 outgoing requests.
1248
1249 Keyword argument:
1250 transport -- Transport object.
1251
1252 """
Benny Prijono55040452008-07-21 18:20:57 +00001253 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001254 err = _pjsua.acc_set_transport(self._id, transport._id)
Benny Prijono55040452008-07-21 18:20:57 +00001255 self._lib()._err_check("set_transport()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001256
Benny Prijono55040452008-07-21 18:20:57 +00001257 def make_call(self, dst_uri, cb=None, hdr_list=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001258 """Make outgoing call to the specified URI.
1259
1260 Keyword arguments:
1261 dst_uri -- Destination SIP URI.
Benny Prijono55040452008-07-21 18:20:57 +00001262 cb -- CallCallback instance to be installed to the newly
1263 created Call object. If this CallCallback is not
1264 specified (i.e. None is given), it must be installed
1265 later using call.set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001266 hdr_list -- Optional list of headers to be sent with outgoing
1267 INVITE
1268
Benny Prijono55040452008-07-21 18:20:57 +00001269 Return:
1270 Call instance.
Benny Prijono9c461142008-07-10 22:41:20 +00001271 """
Benny Prijono55040452008-07-21 18:20:57 +00001272 lck = self._lib().auto_lock()
1273 call = Call(self._lib(), -1, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00001274 err, cid = _pjsua.call_make_call(self._id, dst_uri, 0,
Benny Prijono55040452008-07-21 18:20:57 +00001275 call, Lib._create_msg_data(hdr_list))
1276 self._lib()._err_check("make_call()", self, err)
1277 call.attach_to_id(cid)
1278 return call
Benny Prijono9c461142008-07-10 22:41:20 +00001279
Benny Prijono55040452008-07-21 18:20:57 +00001280 def add_buddy(self, uri, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001281 """Add new buddy.
1282
1283 Keyword argument:
Benny Prijono55040452008-07-21 18:20:57 +00001284 uri -- SIP URI of the buddy
1285 cb -- BuddyCallback instance to be installed to the newly
1286 created Buddy object. If this callback is not specified
1287 (i.e. None is given), it must be installed later using
1288 buddy.set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001289
1290 Return:
1291 Buddy object
1292 """
Benny Prijono55040452008-07-21 18:20:57 +00001293 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001294 buddy_cfg = _pjsua.buddy_config_default()
1295 buddy_cfg.uri = uri
1296 buddy_cfg.subscribe = False
1297 err, buddy_id = _pjsua.buddy_add(buddy_cfg)
Benny Prijono55040452008-07-21 18:20:57 +00001298 self._lib()._err_check("add_buddy()", self, err)
1299 buddy = Buddy(self._lib(), buddy_id, self, cb)
1300 return buddy
Benny Prijono9c461142008-07-10 22:41:20 +00001301
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001302 def pres_notify(self, pres_obj, state, reason="", hdr_list=None):
1303 """Send NOTIFY to inform account presence status or to terminate
1304 server side presence subscription.
1305
1306 Keyword arguments:
1307 pres_obj -- The subscription object from on_incoming_subscribe()
1308 callback
1309 state -- Subscription state, from SubscriptionState
1310 reason -- Optional reason phrase.
1311 hdr_list -- Optional header list.
1312 """
Benny Prijono55040452008-07-21 18:20:57 +00001313 lck = self._lib().auto_lock()
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001314 _pjsua.acc_pres_notify(self._id, pres_obj, state, reason,
1315 Lib._create_msg_data(hdr_list))
Benny Prijono9c461142008-07-10 22:41:20 +00001316
1317class CallCallback:
1318 """Class to receive event notification from Call objects.
1319
1320 Use Call.set_callback() method to install instance of this callback
1321 class to receive event notifications from the call object.
Benny Prijonob85ba652008-07-11 00:55:22 +00001322
1323 Member documentation:
1324
1325 call -- the Call object.
1326
Benny Prijono9c461142008-07-10 22:41:20 +00001327 """
1328 call = None
1329
Benny Prijono55040452008-07-21 18:20:57 +00001330 def __init__(self, call=None):
1331 self._set_call(call)
1332
1333 def __del__(self):
1334 pass
1335
1336 def _set_call(self, call):
1337 if call:
1338 self.call = weakref.proxy(call)
1339 else:
1340 self.call = None
Benny Prijono9c461142008-07-10 22:41:20 +00001341
1342 def on_state(self):
1343 """Notification that the call's state has changed.
1344
1345 """
1346 pass
1347
1348 def on_media_state(self):
1349 """Notification that the call's media state has changed.
1350
1351 """
1352 pass
1353
1354 def on_dtmf_digit(self, digits):
1355 """Notification on incoming DTMF digits.
1356
1357 Keyword argument:
1358 digits -- string containing the received digits.
1359
1360 """
1361 pass
1362
1363 def on_transfer_request(self, dst, code):
1364 """Notification that call is being transfered by remote party.
1365
1366 Application can decide to accept/reject transfer request by returning
1367 code greater than or equal to 500. The default behavior is to accept
1368 the transfer by returning 202.
1369
1370 Keyword arguments:
1371 dst -- string containing the destination URI
1372 code -- the suggested status code to return to accept the request.
1373
1374 Return:
1375 the callback should return 202 to accept the request, or 300-699 to
1376 reject the request.
1377
1378 """
1379 return code
1380
1381 def on_transfer_status(self, code, reason, final, cont):
1382 """
1383 Notification about the status of previous call transfer request.
1384
1385 Keyword arguments:
1386 code -- SIP status code to indicate completion status.
1387 text -- SIP status reason phrase.
1388 final -- if True then this is a final status and no further
1389 notifications will be sent for this call transfer
1390 status.
1391 cont -- suggested return value.
1392
1393 Return:
1394 If the callback returns false then no further notification will
1395 be sent for the transfer request for this call.
1396
1397 """
1398 return cont
1399
1400 def on_replace_request(self, code, reason):
1401 """Notification when incoming INVITE with Replaces header is received.
1402
1403 Application may reject the request by returning value greather than
1404 or equal to 500. The default behavior is to accept the request.
1405
1406 Keyword arguments:
1407 code -- default status code to return
1408 reason -- default reason phrase to return
1409
1410 Return:
1411 The callback should return (code, reason) tuple.
1412
1413 """
1414 return code, reason
1415
1416 def on_replaced(self, new_call):
1417 """
1418 Notification that this call will be replaced with new_call.
1419 After this callback is called, this call will be disconnected.
1420
1421 Keyword arguments:
1422 new_call -- the new call that will replace this call.
1423 """
1424 pass
1425
1426 def on_pager(self, mime_type, body):
1427 """
1428 Notification that incoming instant message is received on
1429 this call.
1430
1431 Keyword arguments:
1432 mime_type -- MIME type of the instant message body.
1433 body -- the instant message body.
1434
1435 """
1436 pass
1437
1438 def on_pager_status(self, body, im_id, code, reason):
1439 """
1440 Notification about the delivery status of previously sent
1441 instant message.
1442
1443 Keyword arguments:
1444 body -- message body
1445 im_id -- message ID
1446 code -- SIP status code
1447 reason -- SIP reason phrase
1448
1449 """
1450 pass
1451
1452 def on_typing(self, is_typing):
1453 """
1454 Notification that remote is typing or stop typing.
1455
1456 Keyword arguments:
1457 is_typing -- boolean to indicate whether remote is currently
1458 typing an instant message.
1459
1460 """
1461 pass
1462
1463
1464class CallInfo:
1465 """This structure contains various information about Call.
1466
1467 Application may retrieve this information with Call.info().
Benny Prijonob85ba652008-07-11 00:55:22 +00001468
1469 Member documentation:
1470
1471 role -- CallRole
1472 account -- Account object.
1473 uri -- SIP URI of local account.
1474 contact -- local Contact URI.
1475 remote_uri -- remote SIP URI.
1476 remote_contact -- remote Contact URI
1477 sip_call_id -- call's Call-ID identification
1478 state -- CallState
1479 state_text -- state text.
1480 last_code -- last SIP status code
1481 last_reason -- text phrase for last_code
1482 media_state -- MediaState
1483 media_dir -- MediaDir
1484 conf_slot -- conference slot number for this call.
1485 call_time -- call's connected duration in seconds.
1486 total_time -- total call duration in seconds.
Benny Prijono9c461142008-07-10 22:41:20 +00001487 """
1488 role = CallRole.CALLER
1489 account = None
1490 uri = ""
1491 contact = ""
1492 remote_uri = ""
1493 remote_contact = ""
1494 sip_call_id = ""
1495 state = CallState.NULL
1496 state_text = ""
1497 last_code = 0
1498 last_reason = ""
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001499 media_state = MediaState.NULL
1500 media_dir = MediaDir.NULL
Benny Prijono9c461142008-07-10 22:41:20 +00001501 conf_slot = -1
1502 call_time = 0
1503 total_time = 0
1504
1505 def __init__(self, lib=None, ci=None):
1506 if lib and ci:
1507 self._cvt_from_pjsua(lib, ci)
1508
1509 def _cvt_from_pjsua(self, lib, ci):
1510 self.role = ci.role
1511 self.account = lib._lookup_account(ci.acc_id)
1512 self.uri = ci.local_info
1513 self.contact = ci.local_contact
1514 self.remote_uri = ci.remote_info
1515 self.remote_contact = ci.remote_contact
1516 self.sip_call_id = ci.call_id
1517 self.state = ci.state
1518 self.state_text = ci.state_text
1519 self.last_code = ci.last_status
1520 self.last_reason = ci.last_status_text
1521 self.media_state = ci.media_status
1522 self.media_dir = ci.media_dir
1523 self.conf_slot = ci.conf_slot
Benny Prijono55040452008-07-21 18:20:57 +00001524 self.call_time = ci.connect_duration / 1000
1525 self.total_time = ci.total_duration / 1000
Benny Prijono9c461142008-07-10 22:41:20 +00001526
1527
1528class Call:
1529 """This class represents SIP call.
1530
1531 Application initiates outgoing call with Account.make_call(), and
1532 incoming calls are reported in AccountCallback.on_incoming_call().
1533 """
1534 _id = -1
1535 _cb = None
1536 _lib = None
1537 _obj_name = ""
1538
Benny Prijono55040452008-07-21 18:20:57 +00001539 def __init__(self, lib, call_id, cb=None):
1540 self._lib = weakref.ref(lib)
1541 self.set_callback(cb)
1542 self.attach_to_id(call_id)
1543 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001544
1545 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001546 if self._id != -1:
1547 _pjsua.call_set_user_data(self._id, 0)
1548 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001549
1550 def __str__(self):
1551 return self._obj_name
1552
Benny Prijono55040452008-07-21 18:20:57 +00001553 def attach_to_id(self, call_id):
1554 lck = self._lib().auto_lock()
1555 if self._id != -1:
1556 _pjsua.call_set_user_data(self._id, 0)
1557 self._id = call_id
1558 if self._id != -1:
1559 _pjsua.call_set_user_data(self._id, self)
1560 self._obj_name = "{Call " + self.info().remote_uri + "}"
1561 else:
1562 self._obj_name = "{Call object}"
1563
Benny Prijono9c461142008-07-10 22:41:20 +00001564 def set_callback(self, cb):
1565 """
1566 Set callback object to retrieve event notifications from this call.
1567
1568 Keyword arguments:
1569 cb -- CallCallback instance.
1570 """
1571 if cb:
1572 self._cb = cb
1573 else:
1574 self._cb = CallCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001575 self._cb._set_call(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001576
1577 def info(self):
1578 """
1579 Get the CallInfo.
1580 """
Benny Prijono55040452008-07-21 18:20:57 +00001581 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001582 ci = _pjsua.call_get_info(self._id)
1583 if not ci:
Benny Prijono55040452008-07-21 18:20:57 +00001584 self._lib()._err_check("info", self, -1, "Invalid call")
1585 call_info = CallInfo(self._lib(), ci)
1586 return call_info
Benny Prijono9c461142008-07-10 22:41:20 +00001587
1588 def is_valid(self):
1589 """
1590 Check if this call is still valid.
1591 """
Benny Prijono55040452008-07-21 18:20:57 +00001592 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001593 return _pjsua.call_is_active(self._id)
1594
1595 def dump_status(self, with_media=True, indent="", max_len=1024):
1596 """
1597 Dump the call status.
1598 """
Benny Prijono55040452008-07-21 18:20:57 +00001599 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001600 return _pjsua.call_dump(self._id, with_media, max_len, indent)
1601
1602 def answer(self, code=200, reason="", hdr_list=None):
1603 """
1604 Send provisional or final response to incoming call.
1605
1606 Keyword arguments:
1607 code -- SIP status code.
1608 reason -- Reason phrase. Put empty to send default reason
1609 phrase for the status code.
1610 hdr_list -- Optional list of headers to be sent with the
1611 INVITE response.
1612
1613 """
Benny Prijono55040452008-07-21 18:20:57 +00001614 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001615 err = _pjsua.call_answer(self._id, code, reason,
1616 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001617 self._lib()._err_check("answer()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001618
1619 def hangup(self, code=603, reason="", hdr_list=None):
1620 """
1621 Terminate the call.
1622
1623 Keyword arguments:
1624 code -- SIP status code.
1625 reason -- Reason phrase. Put empty to send default reason
1626 phrase for the status code.
1627 hdr_list -- Optional list of headers to be sent with the
1628 message.
1629
1630 """
Benny Prijono55040452008-07-21 18:20:57 +00001631 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001632 err = _pjsua.call_hangup(self._id, code, reason,
1633 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001634 self._lib()._err_check("hangup()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001635
1636 def hold(self, hdr_list=None):
1637 """
1638 Put the call on hold.
1639
1640 Keyword arguments:
1641 hdr_list -- Optional list of headers to be sent with the
1642 message.
1643 """
Benny Prijono55040452008-07-21 18:20:57 +00001644 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001645 err = _pjsua.call_set_hold(self._id, Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001646 self._lib()._err_check("hold()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001647
1648 def unhold(self, hdr_list=None):
1649 """
1650 Release the call from hold.
1651
1652 Keyword arguments:
1653 hdr_list -- Optional list of headers to be sent with the
1654 message.
1655
1656 """
Benny Prijono55040452008-07-21 18:20:57 +00001657 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001658 err = _pjsua.call_reinvite(self._id, True,
1659 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001660 self._lib()._err_check("unhold()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001661
1662 def reinvite(self, hdr_list=None):
1663 """
1664 Send re-INVITE and optionally offer new codecs to use.
1665
1666 Keyword arguments:
1667 hdr_list -- Optional list of headers to be sent with the
1668 message.
1669
1670 """
Benny Prijono55040452008-07-21 18:20:57 +00001671 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001672 err = _pjsua.call_reinvite(self._id, True,
1673 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001674 self._lib()._err_check("reinvite()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001675
1676 def update(self, hdr_list=None, options=0):
1677 """
1678 Send UPDATE and optionally offer new codecs to use.
1679
1680 Keyword arguments:
1681 hdr_list -- Optional list of headers to be sent with the
1682 message.
1683 options -- Must be zero for now.
1684
1685 """
Benny Prijono55040452008-07-21 18:20:57 +00001686 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001687 err = _pjsua.call_update(self._id, options,
1688 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001689 self._lib()._err_check("update()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001690
1691 def transfer(self, dest_uri, hdr_list=None):
1692 """
1693 Transfer the call to new destination.
1694
1695 Keyword arguments:
1696 dest_uri -- Specify the SIP URI to transfer the call to.
1697 hdr_list -- Optional list of headers to be sent with the
1698 message.
1699
1700 """
Benny Prijono55040452008-07-21 18:20:57 +00001701 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001702 err = _pjsua.call_xfer(self._id, dest_uri,
1703 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001704 self._lib()._err_check("transfer()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001705
1706 def transfer_to_call(self, call, hdr_list=None, options=0):
1707 """
1708 Attended call transfer.
1709
1710 Keyword arguments:
1711 call -- The Call object to transfer call to.
1712 hdr_list -- Optional list of headers to be sent with the
1713 message.
1714 options -- Must be zero for now.
1715
1716 """
Benny Prijono55040452008-07-21 18:20:57 +00001717 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001718 err = _pjsua.call_xfer_replaces(self._id, call._id, options,
1719 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001720 self._lib()._err_check("transfer_to_call()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001721
1722 def dial_dtmf(self, digits):
1723 """
1724 Send DTMF digits with RTP event package.
1725
1726 Keyword arguments:
1727 digits -- DTMF digit string.
1728
1729 """
Benny Prijono55040452008-07-21 18:20:57 +00001730 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001731 err = _pjsua.call_dial_dtmf(self._id, digits)
Benny Prijono55040452008-07-21 18:20:57 +00001732 self._lib()._err_check("dial_dtmf()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001733
1734 def send_request(self, method, hdr_list=None, content_type=None,
1735 body=None):
1736 """
1737 Send arbitrary request to remote call.
1738
1739 This is useful for example to send INFO request. Note that this
1740 function should not be used to send request that will change the
1741 call state such as CANCEL or BYE.
1742
1743 Keyword arguments:
1744 method -- SIP method name.
1745 hdr_list -- Optional header list to be sent with the request.
1746 content_type -- Content type to describe the body, if the body
1747 is present
1748 body -- Optional SIP message body.
1749
1750 """
Benny Prijono55040452008-07-21 18:20:57 +00001751 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001752 if hdr_list and body:
1753 msg_data = _pjsua.Msg_Data()
1754 if hdr_list:
1755 msg_data.hdr_list = hdr_list
1756 if content_type:
1757 msg_data.content_type = content_type
1758 if body:
1759 msg_data.msg_body = body
1760 else:
1761 msg_data = None
1762
1763 err = _pjsua.call_send_request(self._id, method, msg_data)
Benny Prijono55040452008-07-21 18:20:57 +00001764 self._lib()._err_check("send_request()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001765
1766
1767class BuddyInfo:
1768 """This class contains information about Buddy. Application may
1769 retrieve this information by calling Buddy.info().
Benny Prijonob85ba652008-07-11 00:55:22 +00001770
1771 Member documentation:
1772
1773 uri -- the Buddy URI.
1774 contact -- the Buddy Contact URI, if available.
1775 online_status -- the presence online status.
1776 online_text -- the presence online status text.
1777 activity -- the PresenceActivity
1778 subscribed -- specify whether buddy's presence status is currently
1779 being subscribed.
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001780 sub_state -- SubscriptionState
1781 sub_term_reason -- The termination reason string of the last presence
1782 subscription to this buddy, if any.
Benny Prijono9c461142008-07-10 22:41:20 +00001783 """
1784 uri = ""
1785 contact = ""
1786 online_status = 0
1787 online_text = ""
1788 activity = PresenceActivity.UNKNOWN
1789 subscribed = False
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001790 sub_state = SubscriptionState.NULL
1791 sub_term_reason = ""
Benny Prijono9c461142008-07-10 22:41:20 +00001792
1793 def __init__(self, pjsua_bi=None):
1794 if pjsua_bi:
1795 self._cvt_from_pjsua(pjsua_bi)
1796
1797 def _cvt_from_pjsua(self, inf):
1798 self.uri = inf.uri
1799 self.contact = inf.contact
1800 self.online_status = inf.status
1801 self.online_text = inf.status_text
1802 self.activity = inf.activity
1803 self.subscribed = inf.monitor_pres
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001804 self.sub_state = inf.sub_state
1805 self.sub_term_reason = inf.sub_term_reason
Benny Prijono9c461142008-07-10 22:41:20 +00001806
1807
1808class BuddyCallback:
1809 """This class can be used to receive notifications about Buddy's
1810 presence status change. Application needs to derive a class from
1811 this class, and register the instance with Buddy.set_callback().
Benny Prijonob85ba652008-07-11 00:55:22 +00001812
1813 Member documentation:
1814
1815 buddy -- the Buddy object.
Benny Prijono9c461142008-07-10 22:41:20 +00001816 """
1817 buddy = None
1818
Benny Prijono55040452008-07-21 18:20:57 +00001819 def __init__(self, buddy=None):
1820 self._set_buddy(buddy)
1821
1822 def _set_buddy(self, buddy):
1823 if buddy:
1824 self.buddy = weakref.proxy(buddy)
1825 else:
1826 self.buddy = None
Benny Prijono9c461142008-07-10 22:41:20 +00001827
1828 def on_state(self):
1829 """
1830 Notification that buddy's presence state has changed. Application
1831 may then retrieve the new status with Buddy.info() function.
1832 """
1833 pass
1834
1835 def on_pager(self, mime_type, body):
1836 """Notification that incoming instant message is received from
1837 this buddy.
1838
1839 Keyword arguments:
1840 mime_type -- MIME type of the instant message body
1841 body -- the instant message body
1842
1843 """
1844 pass
1845
1846 def on_pager_status(self, body, im_id, code, reason):
1847 """Notification about the delivery status of previously sent
1848 instant message.
1849
1850 Keyword arguments:
1851 body -- the message body
1852 im_id -- message ID
1853 code -- SIP status code
1854 reason -- SIP reason phrase
1855
1856 """
1857 pass
1858
1859 def on_typing(self, is_typing):
1860 """Notification that remote is typing or stop typing.
1861
1862 Keyword arguments:
1863 is_typing -- boolean to indicate whether remote is currently
1864 typing an instant message.
1865
1866 """
1867 pass
1868
1869
1870class Buddy:
1871 """A Buddy represents person or remote agent.
1872
1873 This class provides functions to subscribe to buddy's presence and
1874 to send or receive instant messages from the buddy.
1875 """
1876 _id = -1
1877 _lib = None
1878 _cb = None
1879 _obj_name = ""
1880 _acc = None
1881
Benny Prijono55040452008-07-21 18:20:57 +00001882 def __init__(self, lib, id, account, cb):
Benny Prijono9c461142008-07-10 22:41:20 +00001883 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +00001884 self._lib = weakref.ref(lib)
1885 self._acc = weakref.ref(account)
1886 self._obj_name = "{Buddy " + self.info().uri + "}"
1887 self.set_callback(cb)
1888 _pjsua.buddy_set_user_data(self._id, self)
1889 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001890
1891 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001892 if self._id != -1:
1893 _pjsua.buddy_set_user_data(self._id, 0)
1894 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001895
1896 def __str__(self):
1897 return self._obj_name
1898
1899 def info(self):
1900 """
1901 Get buddy info as BuddyInfo.
1902 """
Benny Prijono55040452008-07-21 18:20:57 +00001903 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001904 return BuddyInfo(_pjsua.buddy_get_info(self._id))
1905
1906 def set_callback(self, cb):
1907 """Install callback to receive notifications from this object.
1908
1909 Keyword argument:
1910 cb -- BuddyCallback instance.
1911 """
1912 if cb:
1913 self._cb = cb
1914 else:
1915 self._cb = BuddyCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001916 self._cb._set_buddy(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001917
1918 def subscribe(self):
1919 """
1920 Subscribe to buddy's presence status notification.
1921 """
Benny Prijono55040452008-07-21 18:20:57 +00001922 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001923 err = _pjsua.buddy_subscribe_pres(self._id, True)
Benny Prijono55040452008-07-21 18:20:57 +00001924 self._lib()._err_check("subscribe()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001925
1926 def unsubscribe(self):
1927 """
1928 Unsubscribe from buddy's presence status notification.
1929 """
Benny Prijono55040452008-07-21 18:20:57 +00001930 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001931 err = _pjsua.buddy_subscribe_pres(self._id, False)
Benny Prijono55040452008-07-21 18:20:57 +00001932 self._lib()._err_check("unsubscribe()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001933
1934 def delete(self):
1935 """
1936 Remove this buddy from the buddy list.
1937 """
Benny Prijono55040452008-07-21 18:20:57 +00001938 lck = self._lib().auto_lock()
1939 if self._id != -1:
1940 _pjsua.buddy_set_user_data(self._id, 0)
Benny Prijono9c461142008-07-10 22:41:20 +00001941 err = _pjsua.buddy_del(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001942 self._lib()._err_check("delete()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001943
1944 def send_pager(self, text, im_id=0, content_type="text/plain", \
1945 hdr_list=None):
1946 """Send instant message to remote buddy.
1947
1948 Keyword arguments:
1949 text -- Instant message to be sent
1950 im_id -- Optional instant message ID to identify this
1951 instant message when delivery status callback
1952 is called.
1953 content_type -- MIME type identifying the instant message
1954 hdr_list -- Optional list of headers to be sent with the
1955 request.
1956
1957 """
Benny Prijono55040452008-07-21 18:20:57 +00001958 lck = self._lib().auto_lock()
1959 err = _pjsua.im_send(self._acc()._id, self.info().uri, \
Benny Prijono9c461142008-07-10 22:41:20 +00001960 content_type, text, \
1961 Lib._create_msg_data(hdr_list), \
1962 im_id)
Benny Prijono55040452008-07-21 18:20:57 +00001963 self._lib()._err_check("send_pager()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001964
1965 def send_typing_ind(self, is_typing=True, hdr_list=None):
1966 """Send typing indication to remote buddy.
1967
1968 Keyword argument:
1969 is_typing -- boolean to indicate wheter user is typing.
1970 hdr_list -- Optional list of headers to be sent with the
1971 request.
1972
1973 """
Benny Prijono55040452008-07-21 18:20:57 +00001974 lck = self._lib().auto_lock()
1975 err = _pjsua.im_typing(self._acc()._id, self.info().uri, \
Benny Prijono9c461142008-07-10 22:41:20 +00001976 is_typing, Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001977 self._lib()._err_check("send_typing_ind()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001978
1979
1980
1981# Sound device info
1982class SoundDeviceInfo:
Benny Prijonob85ba652008-07-11 00:55:22 +00001983 """This described the sound device info.
1984
1985 Member documentation:
1986 name -- device name.
1987 input_channels -- number of capture channels supported.
1988 output_channels -- number of playback channels supported.
1989 default_clock_rate -- default sampling rate.
1990 """
Benny Prijono9c461142008-07-10 22:41:20 +00001991 name = ""
1992 input_channels = 0
Benny Prijonob85ba652008-07-11 00:55:22 +00001993 output_channels = 0
Benny Prijono9c461142008-07-10 22:41:20 +00001994 default_clock_rate = 0
1995
1996 def __init__(self, sdi):
1997 self.name = sdi.name
1998 self.input_channels = sdi.input_count
1999 self.output_channels = sdi.output_count
2000 self.default_clock_rate = sdi.default_samples_per_sec
2001
2002
2003# Codec info
2004class CodecInfo:
Benny Prijonob85ba652008-07-11 00:55:22 +00002005 """This describes codec info.
2006
2007 Member documentation:
2008 name -- codec name
2009 priority -- codec priority (0-255)
2010 clock_rate -- clock rate
2011 channel_count -- number of channels
2012 avg_bps -- average bandwidth in bits per second
2013 frm_ptime -- base frame length in milliseconds
2014 ptime -- RTP frame length in milliseconds.
2015 pt -- payload type.
2016 vad_enabled -- specify if Voice Activity Detection is currently
2017 enabled.
2018 plc_enabled -- specify if Packet Lost Concealment is currently
2019 enabled.
2020 """
Benny Prijono9c461142008-07-10 22:41:20 +00002021 name = ""
2022 priority = 0
2023 clock_rate = 0
2024 channel_count = 0
2025 avg_bps = 0
2026 frm_ptime = 0
2027 ptime = 0
2028 pt = 0
2029 vad_enabled = False
2030 plc_enabled = False
2031
2032 def __init__(self, codec_info, codec_param):
2033 self.name = codec_info.id
2034 self.priority = codec_info.priority
2035 self.clock_rate = codec_param.info.clock_rate
2036 self.channel_count = codec_param.info.channel_count
2037 self.avg_bps = codec_param.info.avg_bps
2038 self.frm_ptime = codec_param.info.frm_ptime
2039 self.ptime = codec_param.info.frm_ptime * \
2040 codec_param.setting.frm_per_pkt
2041 self.ptime = codec_param.info.pt
2042 self.vad_enabled = codec_param.setting.vad
2043 self.plc_enabled = codec_param.setting.plc
2044
2045 def _cvt_to_pjsua(self):
2046 ci = _pjsua.Codec_Info()
2047 ci.id = self.name
2048 ci.priority = self.priority
2049 return ci
2050
2051
2052# Codec parameter
2053class CodecParameter:
Benny Prijonob85ba652008-07-11 00:55:22 +00002054 """This specifies various parameters that can be configured for codec.
2055
2056 Member documentation:
2057
2058 ptime -- specify the outgoing RTP packet length in milliseconds.
2059 vad_enabled -- specify if VAD should be enabled.
2060 plc_enabled -- specify if PLC should be enabled.
2061 """
Benny Prijono9c461142008-07-10 22:41:20 +00002062 ptime = 0
2063 vad_enabled = False
2064 plc_enabled = False
2065 _codec_param = None
2066
2067 def __init__(self, codec_param):
2068 self.ptime = codec_param.info.frm_ptime * \
2069 codec_param.setting.frm_per_pkt
2070 self.vad_enabled = codec_param.setting.vad
2071 self.plc_enabled = codec_param.setting.plc
2072 self._codec_param = codec_param
2073
2074 def _cvt_to_pjsua(self):
2075 self._codec_param.setting.frm_per_pkt = self.ptime / \
2076 self._codec_param.info.frm_ptime
2077 self._codec_param.setting.vad = self.vad_enabled
2078 self._codec_param.setting.plc = self.plc_enabled
2079 return self._codec_param
2080
2081
Benny Prijono55040452008-07-21 18:20:57 +00002082# Library mutex
2083class _LibMutex:
2084 def __init__(self, lck):
2085 self._lck = lck
2086 self._lck.acquire()
2087 #print 'lck acquire'
2088
2089 def __del__(self):
2090 self._lck.release()
2091 #print 'lck release'
2092
2093
Benny Prijono9c461142008-07-10 22:41:20 +00002094# PJSUA Library
2095_lib = None
2096class Lib:
2097 """Library instance.
2098
2099 """
Benny Prijono9c461142008-07-10 22:41:20 +00002100 _quit = False
2101 _has_thread = False
Benny Prijono55040452008-07-21 18:20:57 +00002102 _lock = None
Benny Prijono9c461142008-07-10 22:41:20 +00002103
2104 def __init__(self):
2105 global _lib
2106 if _lib:
2107 raise Error("__init()__", None, -1,
2108 "Library instance already exist")
Benny Prijono55040452008-07-21 18:20:57 +00002109
2110 self._lock = threading.RLock()
Benny Prijono9c461142008-07-10 22:41:20 +00002111 err = _pjsua.create()
2112 self._err_check("_pjsua.create()", None, err)
2113 _lib = self
2114
2115 def __del__(self):
2116 _pjsua.destroy()
Benny Prijono55040452008-07-21 18:20:57 +00002117 del self._lock
2118 print 'Lib destroyed'
Benny Prijono9c461142008-07-10 22:41:20 +00002119
2120 def __str__(self):
2121 return "Lib"
2122
2123 @staticmethod
2124 def instance():
2125 """Return singleton instance of Lib.
2126 """
2127 return _lib
2128
2129 def init(self, ua_cfg=None, log_cfg=None, media_cfg=None):
2130 """
2131 Initialize pjsua with the specified configurations.
2132
2133 Keyword arguments:
2134 ua_cfg -- optional UAConfig instance
2135 log_cfg -- optional LogConfig instance
2136 media_cfg -- optional MediaConfig instance
2137
2138 """
2139 if not ua_cfg: ua_cfg = UAConfig()
2140 if not log_cfg: log_cfg = LogConfig()
2141 if not media_cfg: media_cfg = MediaConfig()
2142
2143 py_ua_cfg = ua_cfg._cvt_to_pjsua()
2144 py_ua_cfg.cb.on_call_state = _cb_on_call_state
2145 py_ua_cfg.cb.on_incoming_call = _cb_on_incoming_call
2146 py_ua_cfg.cb.on_call_media_state = _cb_on_call_media_state
2147 py_ua_cfg.cb.on_dtmf_digit = _cb_on_dtmf_digit
2148 py_ua_cfg.cb.on_call_transfer_request = _cb_on_call_transfer_request
2149 py_ua_cfg.cb.on_call_transfer_status = _cb_on_call_transfer_status
2150 py_ua_cfg.cb.on_call_replace_request = _cb_on_call_replace_request
2151 py_ua_cfg.cb.on_call_replaced = _cb_on_call_replaced
2152 py_ua_cfg.cb.on_reg_state = _cb_on_reg_state
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002153 py_ua_cfg.cb.on_incoming_subscribe = _cb_on_incoming_subscribe
Benny Prijono9c461142008-07-10 22:41:20 +00002154 py_ua_cfg.cb.on_buddy_state = _cb_on_buddy_state
2155 py_ua_cfg.cb.on_pager = _cb_on_pager
2156 py_ua_cfg.cb.on_pager_status = _cb_on_pager_status
2157 py_ua_cfg.cb.on_typing = _cb_on_typing
2158
2159 err = _pjsua.init(py_ua_cfg, log_cfg._cvt_to_pjsua(),
Benny Prijono55040452008-07-21 18:20:57 +00002160 media_cfg._cvt_to_pjsua())
Benny Prijono9c461142008-07-10 22:41:20 +00002161 self._err_check("init()", self, err)
2162
2163 def destroy(self):
2164 """Destroy the library, and pjsua."""
2165 global _lib
2166 if self._has_thread:
2167 self._quit = 1
2168 loop = 0
2169 while self._quit != 2 and loop < 400:
Benny Prijono55040452008-07-21 18:20:57 +00002170 self.handle_events(50)
Benny Prijono9c461142008-07-10 22:41:20 +00002171 loop = loop + 1
2172 _pjsua.destroy()
2173 _lib = None
Benny Prijono55040452008-07-21 18:20:57 +00002174
Benny Prijono9c461142008-07-10 22:41:20 +00002175 def start(self, with_thread=True):
2176 """Start the library.
2177
2178 Keyword argument:
2179 with_thread -- specify whether the module should create worker
2180 thread.
2181
2182 """
2183 err = _pjsua.start()
2184 self._err_check("start()", self, err)
2185 self._has_thread = with_thread
2186 if self._has_thread:
2187 thread.start_new(_worker_thread_main, (0,))
2188
2189 def handle_events(self, timeout=50):
2190 """Poll the events from underlying pjsua library.
2191
2192 Application must poll the stack periodically if worker thread
2193 is disable when starting the library.
2194
2195 Keyword argument:
2196 timeout -- in milliseconds.
2197
2198 """
Benny Prijono55040452008-07-21 18:20:57 +00002199 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002200 return _pjsua.handle_events(timeout)
2201
2202 def verify_sip_url(self, sip_url):
2203 """Verify that the specified string is a valid URI.
2204
2205 Keyword argument:
2206 sip_url -- the URL string.
2207
2208 Return:
2209 0 is the the URI is valid, otherwise the appropriate error
2210 code is returned.
2211
2212 """
Benny Prijono55040452008-07-21 18:20:57 +00002213 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002214 return _pjsua.verify_sip_url(sip_url)
2215
2216 def create_transport(self, type, cfg=None):
2217 """Create SIP transport instance of the specified type.
2218
2219 Keyword arguments:
2220 type -- transport type from TransportType constant.
2221 cfg -- TransportConfig instance
2222
2223 Return:
2224 Transport object
2225
2226 """
Benny Prijono55040452008-07-21 18:20:57 +00002227 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002228 if not cfg: cfg=TransportConfig(type)
2229 err, tp_id = _pjsua.transport_create(type, cfg._cvt_to_pjsua())
2230 self._err_check("create_transport()", self, err)
2231 return Transport(self, tp_id)
2232
Benny Prijono55040452008-07-21 18:20:57 +00002233 def create_account(self, acc_config, set_default=True, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00002234 """
2235 Create a new local pjsua account using the specified configuration.
2236
2237 Keyword arguments:
2238 acc_config -- AccountConfig
2239 set_default -- boolean to specify whether to use this as the
2240 default account.
Benny Prijono55040452008-07-21 18:20:57 +00002241 cb -- AccountCallback instance.
Benny Prijono9c461142008-07-10 22:41:20 +00002242
2243 Return:
2244 Account instance
2245
2246 """
Benny Prijono55040452008-07-21 18:20:57 +00002247 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002248 err, acc_id = _pjsua.acc_add(acc_config._cvt_to_pjsua(), set_default)
2249 self._err_check("create_account()", self, err)
Benny Prijono55040452008-07-21 18:20:57 +00002250 return Account(self, acc_id, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00002251
Benny Prijono55040452008-07-21 18:20:57 +00002252 def create_account_for_transport(self, transport, set_default=True,
2253 cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00002254 """Create a new local pjsua transport for the specified transport.
2255
2256 Keyword arguments:
2257 transport -- the Transport instance.
2258 set_default -- boolean to specify whether to use this as the
2259 default account.
Benny Prijono55040452008-07-21 18:20:57 +00002260 cb -- AccountCallback instance.
Benny Prijono9c461142008-07-10 22:41:20 +00002261
2262 Return:
2263 Account instance
2264
2265 """
Benny Prijono55040452008-07-21 18:20:57 +00002266 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002267 err, acc_id = _pjsua.acc_add_local(transport._id, set_default)
2268 self._err_check("create_account_for_transport()", self, err)
Benny Prijono55040452008-07-21 18:20:57 +00002269 return Account(self, acc_id, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00002270
2271 def hangup_all(self):
2272 """Hangup all calls.
2273
2274 """
Benny Prijono55040452008-07-21 18:20:57 +00002275 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002276 _pjsua.call_hangup_all()
2277
2278 # Sound device API
2279
2280 def enum_snd_dev(self):
2281 """Enumerate sound devices in the system.
2282
2283 Return:
Benny Prijono288d4bd2008-07-19 15:40:21 +00002284 list of SoundDeviceInfo. The index of the element specifies
Benny Prijono9c461142008-07-10 22:41:20 +00002285 the device ID for the device.
2286 """
Benny Prijono55040452008-07-21 18:20:57 +00002287 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002288 sdi_list = _pjsua.enum_snd_devs()
Benny Prijono9c461142008-07-10 22:41:20 +00002289 info = []
Benny Prijono288d4bd2008-07-19 15:40:21 +00002290 for sdi in sdi_list:
Benny Prijono9c461142008-07-10 22:41:20 +00002291 info.append(SoundDeviceInfo(sdi))
2292 return info
2293
2294 def get_snd_dev(self):
2295 """Get the device IDs of current sound devices used by pjsua.
2296
2297 Return:
2298 (capture_dev_id, playback_dev_id) tuple
2299 """
Benny Prijono55040452008-07-21 18:20:57 +00002300 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002301 return _pjsua.get_snd_dev()
2302
2303 def set_snd_dev(self, capture_dev, playback_dev):
2304 """Change the current sound devices.
2305
2306 Keyword arguments:
2307 capture_dev -- the device ID of capture device to be used
2308 playback_dev -- the device ID of playback device to be used.
2309
2310 """
Benny Prijono55040452008-07-21 18:20:57 +00002311 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002312 err = _pjsua.set_snd_dev(capture_dev, playback_dev)
2313 self._err_check("set_current_sound_devices()", self, err)
2314
2315 def set_null_snd_dev(self):
2316 """Disable the sound devices. This is useful if the system
2317 does not have sound device installed.
2318
2319 """
Benny Prijono55040452008-07-21 18:20:57 +00002320 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002321 err = _pjsua.set_null_snd_dev()
2322 self._err_check("set_null_snd_dev()", self, err)
2323
2324
2325 # Conference bridge
2326
2327 def conf_get_max_ports(self):
2328 """Get the conference bridge capacity.
2329
2330 Return:
2331 conference bridge capacity.
2332
2333 """
Benny Prijono55040452008-07-21 18:20:57 +00002334 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002335 return _pjsua.conf_get_max_ports()
2336
2337 def conf_connect(self, src_slot, dst_slot):
2338 """Establish unidirectional media flow from souce to sink.
2339
2340 One source may transmit to multiple destinations/sink. And if
2341 multiple sources are transmitting to the same sink, the media
2342 will be mixed together. Source and sink may refer to the same ID,
2343 effectively looping the media.
2344
2345 If bidirectional media flow is desired, application needs to call
2346 this function twice, with the second one having the arguments
2347 reversed.
2348
2349 Keyword arguments:
2350 src_slot -- integer to identify the conference slot number of
2351 the source/transmitter.
2352 dst_slot -- integer to identify the conference slot number of
2353 the destination/receiver.
2354
2355 """
Benny Prijono55040452008-07-21 18:20:57 +00002356 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002357 err = _pjsua.conf_connect(src_slot, dst_slot)
2358 self._err_check("conf_connect()", self, err)
2359
2360 def conf_disconnect(self, src_slot, dst_slot):
2361 """Disconnect media flow from the source to destination port.
2362
2363 Keyword arguments:
2364 src_slot -- integer to identify the conference slot number of
2365 the source/transmitter.
2366 dst_slot -- integer to identify the conference slot number of
2367 the destination/receiver.
2368
2369 """
Benny Prijono55040452008-07-21 18:20:57 +00002370 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002371 err = _pjsua.conf_disconnect(src_slot, dst_slot)
2372 self._err_check("conf_disconnect()", self, err)
2373
Benny Prijono288d4bd2008-07-19 15:40:21 +00002374 def conf_set_tx_level(self, slot, level):
2375 """Adjust the signal level to be transmitted from the bridge to
2376 the specified port by making it louder or quieter.
2377
2378 Keyword arguments:
2379 slot -- integer to identify the conference slot number.
2380 level -- Signal level adjustment. Value 1.0 means no level
2381 adjustment, while value 0 means to mute the port.
2382 """
Benny Prijono55040452008-07-21 18:20:57 +00002383 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002384 err = _pjsua.conf_set_tx_level(slot, level)
2385 self._err_check("conf_set_tx_level()", self, err)
2386
2387 def conf_set_rx_level(self, slot, level):
2388 """Adjust the signal level to be received from the specified port
2389 (to the bridge) by making it louder or quieter.
2390
2391 Keyword arguments:
2392 slot -- integer to identify the conference slot number.
2393 level -- Signal level adjustment. Value 1.0 means no level
2394 adjustment, while value 0 means to mute the port.
2395 """
Benny Prijono55040452008-07-21 18:20:57 +00002396 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002397 err = _pjsua.conf_set_rx_level(slot, level)
2398 self._err_check("conf_set_rx_level()", self, err)
2399
2400 def conf_get_signal_level(self, slot):
2401 """Get last signal level transmitted to or received from the
2402 specified port. The signal levels are float values from 0.0 to 1.0,
2403 with 0.0 indicates no signal, and 1.0 indicates the loudest signal
2404 level.
2405
2406 Keyword arguments:
2407 slot -- integer to identify the conference slot number.
2408
2409 Return value:
2410 (tx_level, rx_level) tuple.
2411 """
Benny Prijono55040452008-07-21 18:20:57 +00002412 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002413 err, tx_level, rx_level = _pjsua.conf_get_signal_level(slot)
2414 self._err_check("conf_get_signal_level()", self, err)
2415 return (tx_level, rx_level)
2416
2417
2418
Benny Prijono9c461142008-07-10 22:41:20 +00002419 # Codecs API
2420
2421 def enum_codecs(self):
2422 """Return list of codecs supported by pjsua.
2423
2424 Return:
Benny Prijono288d4bd2008-07-19 15:40:21 +00002425 list of CodecInfo
Benny Prijono9c461142008-07-10 22:41:20 +00002426
2427 """
Benny Prijono55040452008-07-21 18:20:57 +00002428 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002429 ci_list = _pjsua.enum_codecs()
Benny Prijono9c461142008-07-10 22:41:20 +00002430 codec_info = []
Benny Prijono288d4bd2008-07-19 15:40:21 +00002431 for ci in ci_list:
Benny Prijono9c461142008-07-10 22:41:20 +00002432 cp = _pjsua.codec_get_param(ci.id)
2433 if cp:
2434 codec_info.append(CodecInfo(ci, cp))
2435 return codec_info
2436
2437 def set_codec_priority(self, name, priority):
2438 """Change the codec priority.
2439
2440 Keyword arguments:
2441 name -- Codec name
2442 priority -- Codec priority, which range is 0-255.
2443
2444 """
Benny Prijono55040452008-07-21 18:20:57 +00002445 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002446 err = _pjsua.codec_set_priority(name, priority)
2447 self._err_check("set_codec_priority()", self, err)
2448
2449 def get_codec_parameter(self, name):
2450 """Get codec parameter for the specified codec.
2451
2452 Keyword arguments:
2453 name -- codec name.
2454
2455 """
Benny Prijono55040452008-07-21 18:20:57 +00002456 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002457 cp = _pjsua.codec_get_param(name)
2458 if not cp:
2459 self._err_check("get_codec_parameter()", self, -1,
2460 "Invalid codec name")
2461 return CodecParameter(cp)
2462
2463 def set_codec_parameter(self, name, param):
2464 """Modify codec parameter for the specified codec.
2465
2466 Keyword arguments:
2467 name -- codec name
2468 param -- codec parameter.
2469
2470 """
Benny Prijono55040452008-07-21 18:20:57 +00002471 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002472 err = _pjsua.codec_set_param(name, param._cvt_to_pjsua())
2473 self._err_check("set_codec_parameter()", self, err)
2474
2475 # WAV playback and recording
2476
2477 def create_player(self, filename, loop=False):
2478 """Create WAV file player.
2479
2480 Keyword arguments
2481 filename -- WAV file name
Benny Prijono288d4bd2008-07-19 15:40:21 +00002482 loop -- boolean to specify whether playback should
2483 automatically restart upon EOF
Benny Prijono9c461142008-07-10 22:41:20 +00002484 Return:
2485 WAV player ID
2486
2487 """
Benny Prijono55040452008-07-21 18:20:57 +00002488 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002489 opt = 0
2490 if not loop:
2491 opt = opt + 1
2492 err, player_id = _pjsua.player_create(filename, opt)
2493 self._err_check("create_player()", self, err)
2494 return player_id
2495
2496 def player_get_slot(self, player_id):
2497 """Get the conference port ID for the specified player.
2498
2499 Keyword arguments:
2500 player_id -- the WAV player ID
2501
2502 Return:
2503 Conference slot number for the player
2504
2505 """
Benny Prijono55040452008-07-21 18:20:57 +00002506 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002507 slot = _pjsua.player_get_conf_port(player_id)
Benny Prijono940bd3e2008-07-11 09:14:40 +00002508 if slot < 0:
2509 self._err_check("player_get_slot()", self, -1,
2510 "Invalid player id")
Benny Prijono9c461142008-07-10 22:41:20 +00002511 return slot
2512
2513 def player_set_pos(self, player_id, pos):
2514 """Set WAV playback position.
2515
2516 Keyword arguments:
2517 player_id -- WAV player ID
2518 pos -- playback position, in samples
2519
2520 """
Benny Prijono55040452008-07-21 18:20:57 +00002521 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002522 err = _pjsua.player_set_pos(player_id, pos)
2523 self._err_check("player_set_pos()", self, err)
2524
2525 def player_destroy(self, player_id):
2526 """Destroy the WAV player.
2527
2528 Keyword arguments:
2529 player_id -- the WAV player ID.
2530
2531 """
Benny Prijono55040452008-07-21 18:20:57 +00002532 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002533 err = _pjsua.player_destroy(player_id)
2534 self._err_check("player_destroy()", self, err)
2535
Benny Prijono288d4bd2008-07-19 15:40:21 +00002536 def create_playlist(self, filelist, label="playlist", loop=True):
2537 """Create WAV playlist.
2538
2539 Keyword arguments:
2540 filelist -- List of WAV file names.
2541 label -- Optional name to be assigned to the playlist
2542 object (useful for logging)
2543 loop -- boolean to specify whether playback should
2544 automatically restart upon EOF
2545
2546 Return:
2547 playlist_id
2548 """
Benny Prijono55040452008-07-21 18:20:57 +00002549 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002550 opt = 0
2551 if not loop:
2552 opt = opt + 1
2553 err, playlist_id = _pjsua.playlist_create(label, filelist, opt)
2554 self._err_check("create_playlist()", self, err)
2555 return playlist_id
2556
2557 def playlist_get_slot(self, playlist_id):
2558 """Get the conference port ID for the specified playlist.
2559
2560 Keyword arguments:
2561 playlist_id -- the WAV playlist ID
2562
2563 Return:
2564 Conference slot number for the playlist
2565
2566 """
Benny Prijono55040452008-07-21 18:20:57 +00002567 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002568 slot = _pjsua.player_get_conf_port(playlist_id)
2569 if slot < 0:
2570 self._err_check("playlist_get_slot()", self, -1,
2571 "Invalid playlist id")
2572 return slot
2573
2574 def playlist_destroy(self, playlist_id):
2575 """Destroy the WAV playlist.
2576
2577 Keyword arguments:
2578 playlist_id -- the WAV playlist ID.
2579
2580 """
Benny Prijono55040452008-07-21 18:20:57 +00002581 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002582 err = _pjsua.player_destroy(playlist_id)
2583 self._err_check("playlist_destroy()", self, err)
2584
Benny Prijono9c461142008-07-10 22:41:20 +00002585 def create_recorder(self, filename):
2586 """Create WAV file recorder.
2587
2588 Keyword arguments
2589 filename -- WAV file name
2590
2591 Return:
2592 WAV recorder ID
2593
2594 """
Benny Prijono55040452008-07-21 18:20:57 +00002595 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002596 err, rec_id = _pjsua.recorder_create(filename, 0, None, -1, 0)
2597 self._err_check("create_recorder()", self, err)
2598 return rec_id
2599
2600 def recorder_get_slot(self, rec_id):
2601 """Get the conference port ID for the specified recorder.
2602
2603 Keyword arguments:
2604 rec_id -- the WAV recorder ID
2605
2606 Return:
2607 Conference slot number for the recorder
2608
2609 """
Benny Prijono55040452008-07-21 18:20:57 +00002610 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002611 slot = _pjsua.recorder_get_conf_port(rec_id)
Benny Prijono940bd3e2008-07-11 09:14:40 +00002612 if slot < 1:
2613 self._err_check("recorder_get_slot()", self, -1,
2614 "Invalid recorder id")
Benny Prijono9c461142008-07-10 22:41:20 +00002615 return slot
2616
2617 def recorder_destroy(self, rec_id):
2618 """Destroy the WAV recorder.
2619
2620 Keyword arguments:
2621 rec_id -- the WAV recorder ID.
2622
2623 """
Benny Prijono55040452008-07-21 18:20:57 +00002624 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002625 err = _pjsua.recorder_destroy(rec_id)
2626 self._err_check("recorder_destroy()", self, err)
2627
2628
2629 # Internal functions
2630
2631 @staticmethod
2632 def strerror(err):
2633 return _pjsua.strerror(err)
2634
2635 def _err_check(self, op_name, obj, err_code, err_msg=""):
2636 if err_code != 0:
2637 raise Error(op_name, obj, err_code, err_msg)
2638
2639 @staticmethod
2640 def _create_msg_data(hdr_list):
2641 if not hdr_list:
2642 return None
2643 msg_data = _pjsua.Msg_Data()
2644 msg_data.hdr_list = hdr_list
2645 return msg_data
2646
Benny Prijono55040452008-07-21 18:20:57 +00002647 def auto_lock(self):
2648 return _LibMutex(self._lock)
2649
Benny Prijono9c461142008-07-10 22:41:20 +00002650 # Internal dictionary manipulation for calls, accounts, and buddies
2651
Benny Prijono9c461142008-07-10 22:41:20 +00002652 def _lookup_call(self, call_id):
Benny Prijono55040452008-07-21 18:20:57 +00002653 return _pjsua.call_get_user_data(call_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002654
2655 def _lookup_account(self, acc_id):
Benny Prijono55040452008-07-21 18:20:57 +00002656 return _pjsua.acc_get_user_data(acc_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002657
2658 def _lookup_buddy(self, buddy_id, uri=None):
Benny Prijono55040452008-07-21 18:20:57 +00002659 if buddy_id != -1:
2660 buddy = _pjsua.buddy_get_user_data(buddy_id)
2661 elif uri:
2662 buddy_id = _pjsua.buddy_find(uri)
2663 if buddy_id != -1:
2664 buddy = _pjsua.buddy_get_user_data(buddy_id)
2665 else:
2666 buddy = None
2667 else:
2668 buddy = None
2669
Benny Prijono9c461142008-07-10 22:41:20 +00002670 return buddy
2671
Benny Prijono9c461142008-07-10 22:41:20 +00002672 # Account allbacks
2673
2674 def _cb_on_reg_state(self, acc_id):
2675 acc = self._lookup_account(acc_id)
2676 if acc:
2677 acc._cb.on_reg_state()
2678
Benny Prijono55040452008-07-21 18:20:57 +00002679 def _cb_on_incoming_subscribe(self, acc_id, buddy_id, from_uri,
2680 contact_uri, pres_obj):
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002681 acc = self._lookup_account(acc_id)
2682 if acc:
2683 buddy = self._lookup_buddy(buddy_id)
Benny Prijono55040452008-07-21 18:20:57 +00002684 return acc._cb.on_incoming_subscribe(buddy, from_uri, contact_uri,
2685 pres_obj)
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002686 else:
2687 return (404, None)
2688
Benny Prijono9c461142008-07-10 22:41:20 +00002689 def _cb_on_incoming_call(self, acc_id, call_id, rdata):
2690 acc = self._lookup_account(acc_id)
2691 if acc:
2692 acc._cb.on_incoming_call( Call(self, call_id) )
2693 else:
2694 _pjsua.call_hangup(call_id, 603, None, None)
2695
2696 # Call callbacks
2697
2698 def _cb_on_call_state(self, call_id):
2699 call = self._lookup_call(call_id)
2700 if call:
Benny Prijono55040452008-07-21 18:20:57 +00002701 if call._id == -1:
2702 call.attach_to_id(call_id)
2703 done = (call.info().state == CallState.DISCONNECTED)
Benny Prijono9c461142008-07-10 22:41:20 +00002704 call._cb.on_state()
Benny Prijono55040452008-07-21 18:20:57 +00002705 if done:
2706 _pjsua.call_set_user_data(call_id, 0)
2707 else:
2708 pass
Benny Prijono9c461142008-07-10 22:41:20 +00002709
2710 def _cb_on_call_media_state(self, call_id):
2711 call = self._lookup_call(call_id)
2712 if call:
2713 call._cb.on_media_state()
2714
2715 def _cb_on_dtmf_digit(self, call_id, digits):
2716 call = self._lookup_call(call_id)
2717 if call:
2718 call._cb.on_dtmf_digit(digits)
2719
2720 def _cb_on_call_transfer_request(self, call_id, dst, code):
2721 call = self._lookup_call(call_id)
2722 if call:
2723 return call._cb.on_transfer_request(dst, code)
2724 else:
2725 return 603
2726
2727 def _cb_on_call_transfer_status(self, call_id, code, text, final, cont):
2728 call = self._lookup_call(call_id)
2729 if call:
2730 return call._cb.on_transfer_status(code, text, final, cont)
2731 else:
2732 return cont
2733
2734 def _cb_on_call_replace_request(self, call_id, rdata, code, reason):
2735 call = self._lookup_call(call_id)
2736 if call:
2737 return call._cb.on_replace_request(code, reason)
2738 else:
2739 return code, reason
2740
2741 def _cb_on_call_replaced(self, old_call_id, new_call_id):
2742 old_call = self._lookup_call(old_call_id)
2743 new_call = self._lookup_call(new_call_id)
2744 if old_call and new_call:
2745 old_call._cb.on_replaced(new_call)
2746
2747 def _cb_on_pager(self, call_id, from_uri, to_uri, contact, mime_type,
2748 body, acc_id):
2749 call = None
2750 if call_id == -1:
2751 call = self._lookup_call(call_id)
2752 if call:
2753 call._cb.on_pager(mime_type, body)
2754 else:
2755 acc = self._lookup_account(acc_id)
2756 buddy = self._lookup_buddy(-1, from_uri)
2757 if buddy:
2758 buddy._cb.on_pager(mime_type, body)
2759 else:
2760 acc._cb.on_pager(from_uri, contact, mime_type, body)
2761
2762 def _cb_on_pager_status(self, call_id, to_uri, body, user_data,
2763 code, reason, acc_id):
2764 call = None
2765 if call_id == -1:
2766 call = self._lookup_call(call_id)
2767 if call:
2768 call._cb.on_pager_status(body, user_data, code, reason)
2769 else:
2770 acc = self._lookup_account(acc_id)
2771 buddy = self._lookup_buddy(-1, to_uri)
2772 if buddy:
2773 buddy._cb.on_pager_status(body, user_data, code, reason)
2774 else:
2775 acc._cb.on_pager_status(to_uri, body, user_data, code, reason)
2776
2777 def _cb_on_typing(self, call_id, from_uri, to_uri, contact, is_typing,
2778 acc_id):
2779 call = None
2780 if call_id == -1:
2781 call = self._lookup_call(call_id)
2782 if call:
2783 call._cb.on_typing(is_typing)
2784 else:
2785 acc = self._lookup_account(acc_id)
2786 buddy = self._lookup_buddy(-1, from_uri)
2787 if buddy:
2788 buddy._cb.on_typing(is_typing)
2789 else:
2790 acc._cb.on_typing(from_uri, contact, is_typing)
2791
2792 def _cb_on_buddy_state(self, buddy_id):
2793 buddy = self._lookup_buddy(buddy_id)
2794 if buddy:
2795 buddy._cb.on_state()
2796
2797
2798
2799
2800#
2801# Internal
2802#
2803
2804def _cb_on_call_state(call_id, e):
2805 _lib._cb_on_call_state(call_id)
2806
2807def _cb_on_incoming_call(acc_id, call_id, rdata):
2808 _lib._cb_on_incoming_call(acc_id, call_id, rdata)
2809
2810def _cb_on_call_media_state(call_id):
2811 _lib._cb_on_call_media_state(call_id)
2812
2813def _cb_on_dtmf_digit(call_id, digits):
2814 _lib._cb_on_dtmf_digit(call_id, digits)
2815
2816def _cb_on_call_transfer_request(call_id, dst, code):
2817 return _lib._cb_on_call_transfer_request(call_id, dst, code)
2818
2819def _cb_on_call_transfer_status(call_id, code, reason, final, cont):
2820 return _lib._cb_on_call_transfer_status(call_id, code, reason,
2821 final, cont)
2822def _cb_on_call_replace_request(call_id, rdata, code, reason):
2823 return _lib._cb_on_call_replace_request(call_id, rdata, code, reason)
2824
2825def _cb_on_call_replaced(old_call_id, new_call_id):
2826 _lib._cb_on_call_replaced(old_call_id, new_call_id)
2827
2828def _cb_on_reg_state(acc_id):
2829 _lib._cb_on_reg_state(acc_id)
2830
Benny Prijono55040452008-07-21 18:20:57 +00002831def _cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, contact_uri, pres):
2832 return _lib._cb_on_incoming_subscribe(acc_id, buddy_id, from_uri,
2833 contact_uri, pres)
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002834
Benny Prijono9c461142008-07-10 22:41:20 +00002835def _cb_on_buddy_state(buddy_id):
2836 _lib._cb_on_buddy_state(buddy_id)
2837
2838def _cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id):
2839 _lib._cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id)
2840
2841def _cb_on_pager_status(call_id, to, body, user_data, status, reason, acc_id):
2842 _lib._cb_on_pager_status(call_id, to, body, user_data,
2843 status, reason, acc_id)
2844
2845def _cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id):
2846 _lib._cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id)
2847
2848
2849# Worker thread
2850def _worker_thread_main(arg):
2851 global _lib
2852 thread_desc = 0;
2853 err = _pjsua.thread_register("python worker", thread_desc)
2854 _lib._err_check("thread_register()", _lib, err)
Benny Prijono55040452008-07-21 18:20:57 +00002855 while _lib and _lib._quit == 0:
2856 _lib.handle_events(50)
2857 if _lib:
2858 _lib._quit = 2
Benny Prijono9c461142008-07-10 22:41:20 +00002859
Benny Prijono55040452008-07-21 18:20:57 +00002860def _Trace(args):
2861 if True:
2862 print "** ",
2863 for arg in args:
2864 print arg,
2865 print " **"