blob: 89809e97e4d0a91881d445cfca092b9426ff1fc2 [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#
Benny Prijonofd47c2c2008-07-24 09:00:28 +00007# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20#
Benny Prijono9c461142008-07-10 22:41:20 +000021
22"""Multimedia communication client library based on SIP protocol.
23
24This implements a fully featured multimedia communication client
25library based on PJSIP stack (http://www.pjsip.org)
26
27
Benny Prijono288d4bd2008-07-19 15:40:21 +0000281. FEATURES
Benny Prijono9c461142008-07-10 22:41:20 +000029
Benny Prijono288d4bd2008-07-19 15:40:21 +000030 - Session Initiation Protocol (SIP) features:
Benny Prijono9c461142008-07-10 22:41:20 +000031 - Basic registration and call
32 - Multiple accounts
33 - Call hold, attended and unattended call transfer
34 - Presence
35 - Instant messaging
Benny Prijono288d4bd2008-07-19 15:40:21 +000036 - Multiple SIP accounts
37 - Media features:
Benny Prijono9c461142008-07-10 22:41:20 +000038 - Audio
39 - Conferencing
40 - Narrowband and wideband
41 - Codecs: PCMA, PCMU, GSM, iLBC, Speex, G.722, L16
42 - RTP/RTCP
Benny Prijono288d4bd2008-07-19 15:40:21 +000043 - Secure RTP (SRTP)
44 - WAV playback, recording, and playlist
Benny Prijono9c461142008-07-10 22:41:20 +000045 - NAT traversal features
46 - Symmetric RTP
47 - STUN
48 - TURN
49 - ICE
50
51
Benny Prijono288d4bd2008-07-19 15:40:21 +0000522. USING
53
54See http://www.pjsip.org/trac/wiki/Python_SIP_Tutorial for a more thorough
55tutorial. The paragraphs below explain basic tasks on using this module.
56
57
Benny Prijono9c461142008-07-10 22:41:20 +000058"""
59import _pjsua
60import thread
Benny Prijono55040452008-07-21 18:20:57 +000061import threading
62import weakref
Benny Prijono6ecef072008-07-21 22:46:35 +000063import time
Benny Prijono9c461142008-07-10 22:41:20 +000064
65class Error:
Benny Prijonob85ba652008-07-11 00:55:22 +000066 """Error exception class.
67
68 Member documentation:
69
70 op_name -- name of the operation that generated this error.
71 obj -- the object that generated this error.
72 err_code -- the error code.
73
74 """
Benny Prijono9c461142008-07-10 22:41:20 +000075 op_name = ""
76 obj = None
77 err_code = -1
78 _err_msg = ""
79
80 def __init__(self, op_name, obj, err_code, err_msg=""):
81 self.op_name = op_name
82 self.obj = obj
83 self.err_code = err_code
84 self._err_msg = err_msg
85
86 def err_msg(self):
87 "Retrieve the description of the error."
88 if self._err_msg != "":
89 return self._err_msg
90 self._err_msg = Lib.strerror(self.err_code)
91 return self._err_msg
92
93 def __str__(self):
94 return "Object: " + str(self.obj) + ", operation=" + self.op_name + \
95 ", error=" + self.err_msg()
96
97#
98# Constants
99#
100
101class TransportType:
Benny Prijonob85ba652008-07-11 00:55:22 +0000102 """SIP transport type constants.
103
104 Member documentation:
105 UNSPECIFIED -- transport type is unknown or unspecified
106 UDP -- UDP transport
107 TCP -- TCP transport
108 TLS -- TLS transport
109 IPV6 -- this is not a transport type but rather a flag
110 to select the IPv6 version of a transport
111 UDP_IPV6 -- IPv6 UDP transport
112 TCP_IPV6 -- IPv6 TCP transport
113 """
Benny Prijono9c461142008-07-10 22:41:20 +0000114 UNSPECIFIED = 0
115 UDP = 1
116 TCP = 2
117 TLS = 3
118 IPV6 = 128
119 UDP_IPV6 = UDP + IPV6
120 TCP_IPV6 = TCP + IPV6
121
122class TransportFlag:
Benny Prijonob85ba652008-07-11 00:55:22 +0000123 """Transport flags to indicate the characteristics of the transport.
124
125 Member documentation:
126
127 RELIABLE -- transport is reliable.
128 SECURE -- transport is secure.
129 DATAGRAM -- transport is datagram based.
130
131 """
Benny Prijono9c461142008-07-10 22:41:20 +0000132 RELIABLE = 1
133 SECURE = 2
134 DATAGRAM = 4
135
136class CallRole:
Benny Prijonob85ba652008-07-11 00:55:22 +0000137 """Call role constants.
138
139 Member documentation:
140
141 CALLER -- role is caller
142 CALLEE -- role is callee
143
144 """
Benny Prijono9c461142008-07-10 22:41:20 +0000145 CALLER = 0
146 CALLEE = 1
147
148class CallState:
Benny Prijonob85ba652008-07-11 00:55:22 +0000149 """Call state constants.
150
151 Member documentation:
152
153 NULL -- call is not initialized.
154 CALLING -- initial INVITE is sent.
155 INCOMING -- initial INVITE is received.
156 EARLY -- provisional response has been sent or received.
157 CONNECTING -- 200/OK response has been sent or received.
158 CONFIRMED -- ACK has been sent or received.
159 DISCONNECTED -- call is disconnected.
160 """
Benny Prijono9c461142008-07-10 22:41:20 +0000161 NULL = 0
162 CALLING = 1
163 INCOMING = 2
164 EARLY = 3
165 CONNECTING = 4
166 CONFIRMED = 5
167 DISCONNECTED = 6
168
169
170class MediaState:
Benny Prijonob85ba652008-07-11 00:55:22 +0000171 """Call media state constants.
172
173 Member documentation:
174
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000175 NULL -- media is not available.
Benny Prijonob85ba652008-07-11 00:55:22 +0000176 ACTIVE -- media is active.
177 LOCAL_HOLD -- media is put on-hold by local party.
178 REMOTE_HOLD -- media is put on-hold by remote party.
179 ERROR -- media error (e.g. ICE negotiation failure).
180 """
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000181 NULL = 0
Benny Prijono9c461142008-07-10 22:41:20 +0000182 ACTIVE = 1
183 LOCAL_HOLD = 2
184 REMOTE_HOLD = 3
185 ERROR = 4
186
187
188class MediaDir:
Benny Prijonob85ba652008-07-11 00:55:22 +0000189 """Media direction constants.
190
191 Member documentation:
192
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000193 NULL -- media is not active
Benny Prijonob85ba652008-07-11 00:55:22 +0000194 ENCODING -- media is active in transmit/encoding direction only.
195 DECODING -- media is active in receive/decoding direction only
196 ENCODING_DECODING -- media is active in both directions.
197 """
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000198 NULL = 0
Benny Prijono9c461142008-07-10 22:41:20 +0000199 ENCODING = 1
200 DECODING = 2
201 ENCODING_DECODING = 3
202
203
204class PresenceActivity:
Benny Prijonob85ba652008-07-11 00:55:22 +0000205 """Presence activities constants.
206
207 Member documentation:
208
209 UNKNOWN -- the person activity is unknown
210 AWAY -- the person is currently away
211 BUSY -- the person is currently engaging in other activity
212 """
Benny Prijono9c461142008-07-10 22:41:20 +0000213 UNKNOWN = 0
214 AWAY = 1
215 BUSY = 2
216
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000217
218class SubscriptionState:
219 """Presence subscription state constants.
220
221 """
222 NULL = 0
223 SENT = 1
224 ACCEPTED = 2
225 PENDING = 3
226 ACTIVE = 4
227 TERMINATED = 5
228 UNKNOWN = 6
229
230
Benny Prijono9c461142008-07-10 22:41:20 +0000231class TURNConnType:
Benny Prijonob85ba652008-07-11 00:55:22 +0000232 """These constants specifies the connection type to TURN server.
233
234 Member documentation:
235 UDP -- use UDP transport.
236 TCP -- use TCP transport.
237 TLS -- use TLS transport.
238 """
Benny Prijono9c461142008-07-10 22:41:20 +0000239 UDP = 17
240 TCP = 6
241 TLS = 255
242
243
244class UAConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000245 """User agent configuration to be specified in Lib.init().
246
247 Member documentation:
248
249 max_calls -- maximum number of calls to be supported.
Benny Prijono288d4bd2008-07-19 15:40:21 +0000250 nameserver -- list of nameserver hostnames or IP addresses. Nameserver
Benny Prijonob85ba652008-07-11 00:55:22 +0000251 must be configured if DNS SRV resolution is desired.
252 stun_domain -- if nameserver is configured, this can be used to query
253 the STUN server with DNS SRV.
254 stun_host -- the hostname or IP address of the STUN server. This will
255 also be used if DNS SRV resolution for stun_domain fails.
256 user_agent -- Optionally specify the user agent name.
257 """
Benny Prijono9c461142008-07-10 22:41:20 +0000258 max_calls = 4
259 nameserver = []
260 stun_domain = ""
261 stun_host = ""
262 user_agent = "pjsip python"
263
264 def _cvt_from_pjsua(self, cfg):
265 self.max_calls = cfg.max_calls
266 self.thread_cnt = cfg.thread_cnt
267 self.nameserver = cfg.nameserver
268 self.stun_domain = cfg.stun_domain
269 self.stun_host = cfg.stun_host
270 self.user_agent = cfg.user_agent
271
272 def _cvt_to_pjsua(self):
273 cfg = _pjsua.config_default()
274 cfg.max_calls = self.max_calls
275 cfg.thread_cnt = 0
276 cfg.nameserver = self.nameserver
277 cfg.stun_domain = self.stun_domain
278 cfg.stun_host = self.stun_host
279 cfg.user_agent = self.user_agent
280 return cfg
281
282
283class LogConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000284 """Logging configuration to be specified in Lib.init().
285
286 Member documentation:
287
288 msg_logging -- specify if SIP messages should be logged. Set to
289 True.
290 level -- specify the input verbosity level.
291 console_level -- specify the output verbosity level.
292 decor -- specify log decoration.
293 filename -- specify the log filename.
294 callback -- specify callback to be called to write the logging
295 messages. Sample function:
296
297 def log_cb(level, str, len):
298 print str,
299
300 """
Benny Prijono9c461142008-07-10 22:41:20 +0000301 msg_logging = True
302 level = 5
303 console_level = 5
304 decor = 0
305 filename = ""
306 callback = None
307
308 def __init__(self, level=-1, filename="", callback=None,
309 console_level=-1):
310 self._cvt_from_pjsua(_pjsua.logging_config_default())
311 if level != -1:
312 self.level = level
313 if filename != "":
314 self.filename = filename
315 if callback != None:
316 self.callback = callback
317 if console_level != -1:
318 self.console_level = console_level
319
320 def _cvt_from_pjsua(self, cfg):
321 self.msg_logging = cfg.msg_logging
322 self.level = cfg.level
323 self.console_level = cfg.console_level
324 self.decor = cfg.decor
325 self.filename = cfg.log_filename
326 self.callback = cfg.cb
327
328 def _cvt_to_pjsua(self):
329 cfg = _pjsua.logging_config_default()
330 cfg.msg_logging = self.msg_logging
331 cfg.level = self.level
332 cfg.console_level = self.console_level
333 cfg.decor = self.decor
334 cfg.log_filename = self.filename
335 cfg.cb = self.callback
336 return cfg
337
338
339class MediaConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000340 """Media configuration to be specified in Lib.init().
341
342 Member documentation:
343
344 clock_rate -- specify the core clock rate of the audio,
345 most notably the conference bridge.
346 snd_clock_rate -- optionally specify different clock rate for
347 the sound device.
348 snd_auto_close_time -- specify the duration in seconds when the
349 sound device should be closed after inactivity
350 period.
351 channel_count -- specify the number of channels to open the sound
352 device and the conference bridge.
353 audio_frame_ptime -- specify the length of audio frames in millisecond.
354 max_media_ports -- specify maximum number of audio ports to be
355 supported by the conference bridge.
356 quality -- specify the audio quality setting (1-10)
357 ptime -- specify the audio packet length of transmitted
358 RTP packet.
359 no_vad -- disable Voice Activity Detector (VAD) or Silence
360 Detector (SD)
361 ilbc_mode -- specify iLBC codec mode (must be 30 for now)
362 tx_drop_pct -- randomly drop transmitted RTP packets (for
363 simulation). Number is in percent.
364 rx_drop_pct -- randomly drop received RTP packets (for
365 simulation). Number is in percent.
366 ec_options -- Echo Canceller option (specify zero).
367 ec_tail_len -- specify Echo Canceller tail length in milliseconds.
368 Value zero will disable the echo canceller.
369 jb_min -- specify the minimum jitter buffer size in
370 milliseconds. Put -1 for default.
371 jb_max -- specify the maximum jitter buffer size in
372 milliseconds. Put -1 for default.
373 enable_ice -- enable Interactive Connectivity Establishment (ICE)
374 enable_turn -- enable TURN relay. TURN server settings must also
375 be configured.
376 turn_server -- specify the domain or hostname or IP address of
377 the TURN server, in "host[:port]" format.
378 turn_conn_type -- specify connection type to the TURN server, from
379 the TURNConnType constant.
380 turn_cred -- specify AuthCred for the TURN credential.
381 """
Benny Prijono9c461142008-07-10 22:41:20 +0000382 clock_rate = 16000
383 snd_clock_rate = 0
384 snd_auto_close_time = 5
385 channel_count = 1
386 audio_frame_ptime = 20
387 max_media_ports = 32
388 quality = 6
389 ptime = 0
390 no_vad = False
391 ilbc_mode = 30
392 tx_drop_pct = 0
393 rx_drop_pct = 0
394 ec_options = 0
395 ec_tail_len = 256
396 jb_min = -1
397 jb_max = -1
398 enable_ice = True
399 enable_turn = False
400 turn_server = ""
401 turn_conn_type = TURNConnType.UDP
402 turn_cred = None
403
404 def __init__(self):
405 default = _pjsua.media_config_default()
406 self._cvt_from_pjsua(default)
407
408 def _cvt_from_pjsua(self, cfg):
409 self.clock_rate = cfg.clock_rate
410 self.snd_clock_rate = cfg.snd_clock_rate
411 self.snd_auto_close_time = cfg.snd_auto_close_time
412 self.channel_count = cfg.channel_count
413 self.audio_frame_ptime = cfg.audio_frame_ptime
414 self.max_media_ports = cfg.max_media_ports
415 self.quality = cfg.quality
416 self.ptime = cfg.ptime
417 self.no_vad = cfg.no_vad
418 self.ilbc_mode = cfg.ilbc_mode
419 self.tx_drop_pct = cfg.tx_drop_pct
420 self.rx_drop_pct = cfg.rx_drop_pct
421 self.ec_options = cfg.ec_options
422 self.ec_tail_len = cfg.ec_tail_len
423 self.jb_min = cfg.jb_min
424 self.jb_max = cfg.jb_max
425 self.enable_ice = cfg.enable_ice
426 self.enable_turn = cfg.enable_turn
427 self.turn_server = cfg.turn_server
428 self.turn_conn_type = cfg.turn_conn_type
429 if cfg.turn_username:
430 self.turn_cred = AuthCred(cfg.turn_realm, cfg.turn_username,
431 cfg.turn_passwd, cfg.turn_passwd_type)
432 else:
433 self.turn_cred = None
434
435 def _cvt_to_pjsua(self):
436 cfg = _pjsua.media_config_default()
437 cfg.clock_rate = self.clock_rate
438 cfg.snd_clock_rate = self.snd_clock_rate
439 cfg.snd_auto_close_time = self.snd_auto_close_time
440 cfg.channel_count = self.channel_count
441 cfg.audio_frame_ptime = self.audio_frame_ptime
442 cfg.max_media_ports = self.max_media_ports
443 cfg.quality = self.quality
444 cfg.ptime = self.ptime
445 cfg.no_vad = self.no_vad
446 cfg.ilbc_mode = self.ilbc_mode
447 cfg.tx_drop_pct = self.tx_drop_pct
448 cfg.rx_drop_pct = self.rx_drop_pct
449 cfg.ec_options = self.ec_options
450 cfg.ec_tail_len = self.ec_tail_len
451 cfg.jb_min = self.jb_min
452 cfg.jb_max = self.jb_max
453 cfg.enable_ice = self.enable_ice
454 cfg.enable_turn = self.enable_turn
455 cfg.turn_server = self.turn_server
456 cfg.turn_conn_type = self.turn_conn_type
457 if self.turn_cred:
458 cfg.turn_realm = self.turn_cred.realm
459 cfg.turn_username = self.turn_cred.username
460 cfg.turn_passwd_type = self.turn_cred.passwd_type
461 cfg.turn_passwd = self.turn_cred.passwd
462 return cfg
463
464
465class TransportConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000466 """SIP transport configuration class.
467
468 Member configuration:
469
470 port -- port number.
471 bound_addr -- optionally specify the address to bind the socket to.
472 Default is empty to bind to INADDR_ANY.
473 public_addr -- optionally override the published address for this
474 transport. If empty, the default behavior is to get
475 the public address from STUN or from the selected
476 local interface. Format is "host:port".
477 """
Benny Prijono9c461142008-07-10 22:41:20 +0000478 port = 0
479 bound_addr = ""
480 public_addr = ""
481
Benny Prijonofd47c2c2008-07-24 09:00:28 +0000482 def __init__(self, port=0,
Benny Prijono9c461142008-07-10 22:41:20 +0000483 bound_addr="", public_addr=""):
484 self.port = port
485 self.bound_addr = bound_addr
486 self.public_addr = public_addr
487
488 def _cvt_to_pjsua(self):
489 cfg = _pjsua.transport_config_default()
490 cfg.port = self.port
491 cfg.bound_addr = self.bound_addr
492 cfg.public_addr = self.public_addr
493 return cfg
494
495
496class TransportInfo:
497 """SIP transport info.
Benny Prijonob85ba652008-07-11 00:55:22 +0000498
499 Member documentation:
500
501 type -- transport type, from TransportType constants.
502 description -- longer description for this transport.
503 is_reliable -- True if transport is reliable.
504 is_secure -- True if transport is secure.
505 is_datagram -- True if transport is datagram based.
506 host -- the IP address of this transport.
507 port -- the port number.
508 ref_cnt -- number of objects referencing this transport.
Benny Prijono9c461142008-07-10 22:41:20 +0000509 """
510 type = ""
511 description = ""
512 is_reliable = False
513 is_secure = False
514 is_datagram = False
515 host = ""
516 port = 0
517 ref_cnt = 0
518
519 def __init__(self, ti):
520 self.type = ti.type_name
521 self.description = ti.info
522 self.is_reliable = (ti.flag & TransportFlag.RELIABLE)
523 self.is_secure = (ti.flag & TransportFlag.SECURE)
524 self.is_datagram = (ti.flag & TransportFlag.DATAGRAM)
525 self.host = ti.addr
526 self.port = ti.port
527 self.ref_cnt = ti.usage_count
528
529
530class Transport:
531 "SIP transport class."
532 _id = -1
533 _lib = None
534 _obj_name = ""
535
536 def __init__(self, lib, id):
Benny Prijono55040452008-07-21 18:20:57 +0000537 self._lib = weakref.proxy(lib)
Benny Prijono9c461142008-07-10 22:41:20 +0000538 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +0000539 self._obj_name = "{Transport " + self.info().description + "}"
540 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +0000541
Benny Prijono55040452008-07-21 18:20:57 +0000542 def __del__(self):
543 _Trace((self, 'destroyed'))
544
Benny Prijono9c461142008-07-10 22:41:20 +0000545 def __str__(self):
546 return self._obj_name
547
548 def info(self):
549 """Get TransportInfo.
550 """
Benny Prijono55040452008-07-21 18:20:57 +0000551 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000552 ti = _pjsua.transport_get_info(self._id)
553 if not ti:
554 self._lib._err_check("info()", self, -1, "Invalid transport")
555 return TransportInfo(ti)
556
557 def enable(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000558 """Enable this transport."""
Benny Prijono55040452008-07-21 18:20:57 +0000559 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000560 err = _pjsua.transport_set_enable(self._id, True)
561 self._lib._err_check("enable()", self, err)
562
563 def disable(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000564 """Disable this transport."""
Benny Prijono55040452008-07-21 18:20:57 +0000565 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000566 err = _pjsua.transport_set_enable(self._id, 0)
567 self._lib._err_check("disable()", self, err)
568
569 def close(self, force=False):
Benny Prijonob85ba652008-07-11 00:55:22 +0000570 """Close and destroy this transport.
571
572 Keyword argument:
573 force -- force deletion of this transport (not recommended).
574 """
Benny Prijono55040452008-07-21 18:20:57 +0000575 lck = self._lib.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +0000576 err = _pjsua.transport_close(self._id, force)
577 self._lib._err_check("close()", self, err)
578
579
580class SIPUri:
Benny Prijonob85ba652008-07-11 00:55:22 +0000581 """Helper class to parse the most important components of SIP URI.
582
583 Member documentation:
584
585 scheme -- URI scheme ("sip" or "sips")
586 user -- user part of the URI (may be empty)
587 host -- host name part
588 port -- optional port number (zero if port is not specified).
589 transport -- transport parameter, or empty if transport is not
590 specified.
591
592 """
Benny Prijono9c461142008-07-10 22:41:20 +0000593 scheme = ""
594 user = ""
595 host = ""
596 port = 0
597 transport = ""
598
Benny Prijonob85ba652008-07-11 00:55:22 +0000599 def __init__(self, uri=None):
600 if uri:
601 self.decode(uri)
Benny Prijono9c461142008-07-10 22:41:20 +0000602
603 def decode(self, uri):
Benny Prijonob85ba652008-07-11 00:55:22 +0000604 """Parse SIP URL.
605
606 Keyword argument:
607 uri -- the URI string.
608
609 """
Benny Prijono9c461142008-07-10 22:41:20 +0000610 self.scheme, self.user, self.host, self.port, self.transport = \
611 _pjsua.parse_simple_uri(uri)
612
613 def encode(self):
Benny Prijonob85ba652008-07-11 00:55:22 +0000614 """Encode this object into SIP URI string.
615
616 Return:
617 URI string.
618
619 """
Benny Prijono9c461142008-07-10 22:41:20 +0000620 output = self.scheme + ":"
621 if self.user and len(self.user):
622 output = output + self.user + "@"
623 output = output + self.host
624 if self.port:
625 output = output + ":" + output(self.port)
626 if self.transport:
627 output = output + ";transport=" + self.transport
628 return output
629
Benny Prijonob85ba652008-07-11 00:55:22 +0000630
Benny Prijono9c461142008-07-10 22:41:20 +0000631class AuthCred:
Benny Prijonob85ba652008-07-11 00:55:22 +0000632 """Authentication credential for SIP or TURN account.
633
634 Member documentation:
635
636 scheme -- authentication scheme (default is "Digest")
637 realm -- realm
638 username -- username
639 passwd_type -- password encoding (zero for plain-text)
640 passwd -- the password
641 """
Benny Prijono9c461142008-07-10 22:41:20 +0000642 scheme = "Digest"
643 realm = "*"
644 username = ""
645 passwd_type = 0
646 passwd = ""
647
648 def __init__(self, realm, username, passwd, scheme="Digest", passwd_type=0):
649 self.scheme = scheme
650 self.realm = realm
651 self.username = username
652 self.passwd_type = passwd_type
653 self.passwd = passwd
654
655
656class AccountConfig:
Benny Prijonob85ba652008-07-11 00:55:22 +0000657 """ This describes account configuration to create an account.
658
659 Member documentation:
660
661 priority -- account priority for matching incoming
662 messages.
663 id -- SIP URI of this account. This setting is
664 mandatory.
665 force_contact -- force to use this URI as Contact URI. Setting
666 this value is generally not recommended.
667 reg_uri -- specify the registrar URI. Mandatory if
668 registration is required.
669 reg_timeout -- specify the SIP registration refresh interval
670 in seconds.
671 require_100rel -- specify if reliable provisional response is
672 to be enforced (with Require header).
673 publish_enabled -- specify if PUBLISH should be used. When
674 enabled, the PUBLISH will be sent to the
675 registrar.
676 pidf_tuple_id -- optionally specify the tuple ID in outgoing
677 PIDF document.
678 proxy -- list of proxy URI.
679 auth_cred -- list of AuthCred containing credentials to
680 authenticate against the registrars and
681 the proxies.
682 auth_initial_send -- specify if empty Authorization header should be
683 sent. May be needed for IMS.
684 auth_initial_algorithm -- when auth_initial_send is enabled, optionally
685 specify the authentication algorithm to use.
686 Valid values are "md5", "akav1-md5", or
687 "akav2-md5".
688 transport_id -- optionally specify the transport ID to be used
689 by this account. Shouldn't be needed unless
690 for specific requirements (e.g. in multi-homed
691 scenario).
692 allow_contact_rewrite -- specify whether the account should learn its
693 Contact address from REGISTER response and
694 update the registration accordingly. Default is
695 True.
696 ka_interval -- specify the interval to send NAT keep-alive
697 packet.
698 ka_data -- specify the NAT keep-alive packet contents.
699 use_srtp -- specify the SRTP usage policy. Valid values
700 are: 0=disable, 1=optional, 2=mandatory.
701 Default is 0.
702 srtp_secure_signaling -- specify the signaling security level required
703 by SRTP. Valid values are: 0=no secure
704 transport is required, 1=hop-by-hop secure
705 transport such as TLS is required, 2=end-to-
706 end secure transport is required (i.e. "sips").
Benny Prijono9c461142008-07-10 22:41:20 +0000707 """
708 priority = 0
709 id = ""
710 force_contact = ""
711 reg_uri = ""
712 reg_timeout = 0
713 require_100rel = False
714 publish_enabled = False
715 pidf_tuple_id = ""
716 proxy = []
717 auth_cred = []
718 auth_initial_send = False
719 auth_initial_algorithm = ""
720 transport_id = -1
721 allow_contact_rewrite = True
722 ka_interval = 15
723 ka_data = "\r\n"
724 use_srtp = 0
725 srtp_secure_signaling = 1
726
727 def __init__(self, domain="", username="", password="",
728 display="", registrar="", proxy=""):
729 """
730 Construct account config. If domain argument is specified,
731 a typical configuration will be built.
732
733 Keyword arguments:
734 domain -- domain name of the server.
735 username -- user name.
736 password -- plain-text password.
737 display -- optional display name for the user name.
738 registrar -- the registrar URI. If domain name is specified
739 and this argument is empty, the registrar URI
740 will be constructed from the domain name.
741 proxy -- the proxy URI. If domain name is specified
742 and this argument is empty, the proxy URI
743 will be constructed from the domain name.
744
745 """
746 default = _pjsua.acc_config_default()
747 self._cvt_from_pjsua(default)
748 if domain!="":
749 self.build_config(domain, username, password,
750 display, registrar, proxy)
751
752 def build_config(self, domain, username, password, display="",
753 registrar="", proxy=""):
754 """
755 Construct account config. If domain argument is specified,
756 a typical configuration will be built.
757
758 Keyword arguments:
759 domain -- domain name of the server.
760 username -- user name.
761 password -- plain-text password.
762 display -- optional display name for the user name.
763 registrar -- the registrar URI. If domain name is specified
764 and this argument is empty, the registrar URI
765 will be constructed from the domain name.
766 proxy -- the proxy URI. If domain name is specified
767 and this argument is empty, the proxy URI
768 will be constructed from the domain name.
769
770 """
771 if display != "":
772 display = display + " "
773 userpart = username
774 if userpart != "":
775 userpart = userpart + "@"
776 self.id = display + "<sip:" + userpart + domain + ">"
777 self.reg_uri = registrar
778 if self.reg_uri == "":
779 self.reg_uri = "sip:" + domain
780 if proxy == "":
781 proxy = "sip:" + domain + ";lr"
782 if proxy.find(";lr") == -1:
783 proxy = proxy + ";lr"
784 self.proxy.append(proxy)
785 if username != "":
786 self.auth_cred.append(AuthCred("*", username, password))
787
788 def _cvt_from_pjsua(self, cfg):
789 self.priority = cfg.priority
790 self.id = cfg.id
791 self.force_contact = cfg.force_contact
792 self.reg_uri = cfg.reg_uri
793 self.reg_timeout = cfg.reg_timeout
794 self.require_100rel = cfg.require_100rel
795 self.publish_enabled = cfg.publish_enabled
796 self.pidf_tuple_id = cfg.pidf_tuple_id
797 self.proxy = cfg.proxy
798 for cred in cfg.cred_info:
799 self.auth_cred.append(AuthCred(cred.realm, cred.username,
800 cred.data, cred.scheme,
801 cred.data_type))
802 self.auth_initial_send = cfg.auth_initial_send
803 self.auth_initial_algorithm = cfg.auth_initial_algorithm
804 self.transport_id = cfg.transport_id
805 self.allow_contact_rewrite = cfg.allow_contact_rewrite
806 self.ka_interval = cfg.ka_interval
807 self.ka_data = cfg.ka_data
808 self.use_srtp = cfg.use_srtp
809 self.srtp_secure_signaling = cfg.srtp_secure_signaling
810
811 def _cvt_to_pjsua(self):
812 cfg = _pjsua.acc_config_default()
813 cfg.priority = self.priority
814 cfg.id = self.id
815 cfg.force_contact = self.force_contact
816 cfg.reg_uri = self.reg_uri
817 cfg.reg_timeout = self.reg_timeout
818 cfg.require_100rel = self.require_100rel
819 cfg.publish_enabled = self.publish_enabled
820 cfg.pidf_tuple_id = self.pidf_tuple_id
821 cfg.proxy = self.proxy
822 for cred in self.auth_cred:
823 c = _pjsua.Pjsip_Cred_Info()
824 c.realm = cred.realm
825 c.scheme = cred.scheme
826 c.username = cred.username
827 c.data_type = cred.passwd_type
828 c.data = cred.passwd
829 cfg.cred_info.append(c)
830 cfg.auth_initial_send = self.auth_initial_send
831 cfg.auth_initial_algorithm = self.auth_initial_algorithm
832 cfg.transport_id = self.transport_id
833 cfg.allow_contact_rewrite = self.allow_contact_rewrite
834 cfg.ka_interval = self.ka_interval
835 cfg.ka_data = self.ka_data
836 cfg.use_srtp = self.use_srtp
837 cfg.srtp_secure_signaling = self.srtp_secure_signaling
838 return cfg
839
840
841# Account information
842class AccountInfo:
843 """This describes Account info. Application retrives account info
844 with Account.info().
845
Benny Prijonob85ba652008-07-11 00:55:22 +0000846 Member documentation:
847
848 is_default -- True if this is the default account.
849 uri -- the account URI.
850 reg_active -- True if registration is active for this account.
851 reg_expires -- contains the current registration expiration value,
852 in seconds.
853 reg_status -- the registration status. If the value is less than
854 700, it specifies SIP status code. Value greater than
855 this specifies the error code.
856 reg_reason -- contains the registration status text (e.g. the
857 error message).
858 online_status -- the account's presence online status, True if it's
859 publishing itself as online.
860 online_text -- the account's presence status text.
861
Benny Prijono9c461142008-07-10 22:41:20 +0000862 """
863 is_default = False
864 uri = ""
865 reg_active = False
866 reg_expires = -1
867 reg_status = 0
868 reg_reason = ""
869 online_status = False
870 online_text = ""
871
872 def __init__(self, ai):
873 self.is_default = ai.is_default
874 self.uri = ai.acc_uri
875 self.reg_active = ai.has_registration
876 self.reg_expires = ai.expires
877 self.reg_status = ai.status
878 self.reg_reason = ai.status_text
879 self.online_status = ai.online_status
880 self.online_text = ai.online_status_text
881
882# Account callback
883class AccountCallback:
884 """Class to receive notifications on account's events.
885
886 Derive a class from this class and register it to the Account object
887 using Account.set_callback() to start receiving events from the Account
888 object.
Benny Prijonob85ba652008-07-11 00:55:22 +0000889
890 Member documentation:
891
892 account -- the Account object.
893
Benny Prijono9c461142008-07-10 22:41:20 +0000894 """
895 account = None
896
Benny Prijono55040452008-07-21 18:20:57 +0000897 def __init__(self, account=None):
898 self._set_account(account)
899
900 def __del__(self):
901 pass
902
903 def _set_account(self, account):
904 if account:
905 self.account = weakref.proxy(account)
906 else:
907 self.account = None
Benny Prijono9c461142008-07-10 22:41:20 +0000908
909 def on_reg_state(self):
910 """Notification that the registration status has changed.
911 """
912 pass
913
914 def on_incoming_call(self, call):
915 """Notification about incoming call.
916
917 Unless this callback is implemented, the default behavior is to
918 reject the call with default status code.
919
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000920 Keyword arguments:
921 call -- the new incoming call
Benny Prijono9c461142008-07-10 22:41:20 +0000922 """
923 call.hangup()
924
Benny Prijono55040452008-07-21 18:20:57 +0000925 def on_incoming_subscribe(self, buddy, from_uri, contact_uri, pres_obj):
Benny Prijonoe6787ec2008-07-18 23:00:56 +0000926 """Notification when incoming SUBSCRIBE request is received.
927
928 Application may use this callback to authorize the incoming
929 subscribe request (e.g. ask user permission if the request
930 should be granted)
931
932 Keyword arguments:
933 buddy -- The buddy object, if buddy is found. Otherwise
934 the value is None.
935 from_uri -- The URI string of the sender.
936 pres_obj -- Opaque presence subscription object, which is
937 needed by Account.pres_notify()
938
939 Return:
940 Tuple (code, reason), where:
941 code: The status code. If code is >= 300, the
942 request is rejected. If code is 200, the
943 request is accepted and NOTIFY will be sent
944 automatically. If code is 202, application
945 must accept or reject the request later with
946 Account.press_notify().
947 reason: Optional reason phrase, or None to use the
948 default reasoh phrase for the status code.
949 """
950 return (200, None)
951
Benny Prijono9c461142008-07-10 22:41:20 +0000952 def on_pager(self, from_uri, contact, mime_type, body):
953 """
954 Notification that incoming instant message is received on
955 this account.
956
957 Keyword arguments:
958 from_uri -- sender's URI
959 contact -- sender's Contact URI
960 mime_type -- MIME type of the instant message body
961 body -- the instant message body
962
963 """
964 pass
965
966 def on_pager_status(self, to_uri, body, im_id, code, reason):
967 """
968 Notification about the delivery status of previously sent
969 instant message.
970
971 Keyword arguments:
972 to_uri -- the destination URI of the message
973 body -- the message body
974 im_id -- message ID
975 code -- SIP status code
976 reason -- SIP reason phrase
977
978 """
979 pass
980
981 def on_typing(self, from_uri, contact, is_typing):
982 """
983 Notification that remote is typing or stop typing.
984
985 Keyword arguments:
986 buddy -- Buddy object for the sender, if found. Otherwise
987 this will be None
988 from_uri -- sender's URI of the indication
989 contact -- sender's contact URI
990 is_typing -- boolean to indicate whether remote is currently
991 typing an instant message.
992
993 """
994 pass
995
Benny Prijono6a464882009-10-29 08:16:46 +0000996 def on_mwi_info(self, body):
997 """
998 Notification about change in Message Summary / Message Waiting
999 Indication (RFC 3842) status. MWI subscription must be enabled
1000 in the account config to receive this notification.
1001
1002 Keyword arguments:
1003 body -- String containing message body as received in the
1004 NOTIFY request.
1005
1006 """
1007 pass
1008
Benny Prijono9c461142008-07-10 22:41:20 +00001009
1010
1011class Account:
1012 """This describes SIP account class.
1013
1014 PJSUA accounts provide identity (or identities) of the user who is
1015 currently using the application. In SIP terms, the identity is used
1016 as the From header in outgoing requests.
1017
1018 Account may or may not have client registration associated with it.
1019 An account is also associated with route set and some authentication
1020 credentials, which are used when sending SIP request messages using
1021 the account. An account also has presence's online status, which
1022 will be reported to remote peer when they subscribe to the account's
1023 presence, or which is published to a presence server if presence
1024 publication is enabled for the account.
1025
1026 Account is created with Lib.create_account(). At least one account
1027 MUST be created. If no user association is required, application can
1028 create a userless account by calling Lib.create_account_for_transport().
1029 A userless account identifies local endpoint instead of a particular
1030 user, and it correspond with a particular transport instance.
1031
1032 Also one account must be set as the default account, which is used as
1033 the account to use when PJSUA fails to match a request with any other
1034 accounts.
1035
1036 """
1037 _id = -1
1038 _lib = None
1039 _cb = AccountCallback(None)
1040 _obj_name = ""
1041
Benny Prijono55040452008-07-21 18:20:57 +00001042 def __init__(self, lib, id, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001043 """Construct this class. This is normally called by Lib class and
1044 not by application.
1045
1046 Keyword arguments:
1047 lib -- the Lib instance.
1048 id -- the pjsua account ID.
Benny Prijono55040452008-07-21 18:20:57 +00001049 cb -- AccountCallback instance to receive events from this Account.
1050 If callback is not specified here, it must be set later
1051 using set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001052 """
Benny Prijono9c461142008-07-10 22:41:20 +00001053 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +00001054 self._lib = weakref.ref(lib)
1055 self._obj_name = "{Account " + self.info().uri + "}"
1056 self.set_callback(cb)
1057 _pjsua.acc_set_user_data(self._id, self)
1058 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001059
1060 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001061 if self._id != -1:
1062 _pjsua.acc_set_user_data(self._id, 0)
1063 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001064
1065 def __str__(self):
1066 return self._obj_name
1067
1068 def info(self):
1069 """Retrieve AccountInfo for this account.
1070 """
Benny Prijono55040452008-07-21 18:20:57 +00001071 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001072 ai = _pjsua.acc_get_info(self._id)
1073 if ai==None:
Benny Prijono55040452008-07-21 18:20:57 +00001074 self._lib()._err_check("info()", self, -1, "Invalid account")
Benny Prijono9c461142008-07-10 22:41:20 +00001075 return AccountInfo(ai)
1076
1077 def is_valid(self):
1078 """
1079 Check if this account is still valid.
1080
1081 """
Benny Prijono55040452008-07-21 18:20:57 +00001082 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001083 return _pjsua.acc_is_valid(self._id)
1084
1085 def set_callback(self, cb):
1086 """Register callback to receive notifications from this object.
1087
1088 Keyword argument:
1089 cb -- AccountCallback instance.
1090
1091 """
1092 if cb:
1093 self._cb = cb
1094 else:
1095 self._cb = AccountCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001096 self._cb._set_account(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001097
1098 def set_default(self):
1099 """ Set this account as default account to send outgoing requests
1100 and as the account to receive incoming requests when more exact
1101 matching criteria fails.
1102 """
Benny Prijono55040452008-07-21 18:20:57 +00001103 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001104 err = _pjsua.acc_set_default(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001105 self._lib()._err_check("set_default()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001106
1107 def is_default(self):
1108 """ Check if this account is the default account.
1109
1110 """
Benny Prijono55040452008-07-21 18:20:57 +00001111 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001112 def_id = _pjsua.acc_get_default()
1113 return self.is_valid() and def_id==self._id
1114
1115 def delete(self):
1116 """ Delete this account.
1117
1118 """
Benny Prijono55040452008-07-21 18:20:57 +00001119 lck = self._lib().auto_lock()
1120 err = _pjsua.acc_set_user_data(self._id, 0)
1121 self._lib()._err_check("delete()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001122 err = _pjsua.acc_del(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001123 self._lib()._err_check("delete()", self, err)
1124 self._id = -1
Benny Prijono9c461142008-07-10 22:41:20 +00001125
1126 def set_basic_status(self, is_online):
1127 """ Set basic presence status of this account.
1128
1129 Keyword argument:
1130 is_online -- boolean to indicate basic presence availability.
1131
1132 """
Benny Prijono55040452008-07-21 18:20:57 +00001133 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001134 err = _pjsua.acc_set_online_status(self._id, is_online)
Benny Prijono55040452008-07-21 18:20:57 +00001135 self._lib()._err_check("set_basic_status()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001136
1137 def set_presence_status(self, is_online,
1138 activity=PresenceActivity.UNKNOWN,
1139 pres_text="", rpid_id=""):
1140 """ Set presence status of this account.
1141
1142 Keyword arguments:
1143 is_online -- boolean to indicate basic presence availability
1144 activity -- value from PresenceActivity
1145 pres_text -- optional string to convey additional information about
1146 the activity (such as "On the phone")
1147 rpid_id -- optional string to be placed as RPID ID.
1148
1149 """
Benny Prijono55040452008-07-21 18:20:57 +00001150 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001151 err = _pjsua.acc_set_online_status2(self._id, is_online, activity,
1152 pres_text, rpid_id)
Benny Prijono55040452008-07-21 18:20:57 +00001153 self._lib()._err_check("set_presence_status()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001154
1155 def set_registration(self, renew):
1156 """Manually renew registration or unregister from the server.
1157
1158 Keyword argument:
1159 renew -- boolean to indicate whether registration is renewed.
1160 Setting this value for False will trigger unregistration.
1161
1162 """
Benny Prijono55040452008-07-21 18:20:57 +00001163 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001164 err = _pjsua.acc_set_registration(self._id, renew)
Benny Prijono55040452008-07-21 18:20:57 +00001165 self._lib()._err_check("set_registration()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001166
1167 def set_transport(self, transport):
1168 """Set this account to only use the specified transport to send
1169 outgoing requests.
1170
1171 Keyword argument:
1172 transport -- Transport object.
1173
1174 """
Benny Prijono55040452008-07-21 18:20:57 +00001175 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001176 err = _pjsua.acc_set_transport(self._id, transport._id)
Benny Prijono55040452008-07-21 18:20:57 +00001177 self._lib()._err_check("set_transport()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001178
Benny Prijono55040452008-07-21 18:20:57 +00001179 def make_call(self, dst_uri, cb=None, hdr_list=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001180 """Make outgoing call to the specified URI.
1181
1182 Keyword arguments:
1183 dst_uri -- Destination SIP URI.
Benny Prijono55040452008-07-21 18:20:57 +00001184 cb -- CallCallback instance to be installed to the newly
1185 created Call object. If this CallCallback is not
1186 specified (i.e. None is given), it must be installed
1187 later using call.set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001188 hdr_list -- Optional list of headers to be sent with outgoing
1189 INVITE
1190
Benny Prijono55040452008-07-21 18:20:57 +00001191 Return:
1192 Call instance.
Benny Prijono9c461142008-07-10 22:41:20 +00001193 """
Benny Prijono55040452008-07-21 18:20:57 +00001194 lck = self._lib().auto_lock()
1195 call = Call(self._lib(), -1, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00001196 err, cid = _pjsua.call_make_call(self._id, dst_uri, 0,
Benny Prijono55040452008-07-21 18:20:57 +00001197 call, Lib._create_msg_data(hdr_list))
1198 self._lib()._err_check("make_call()", self, err)
1199 call.attach_to_id(cid)
1200 return call
Benny Prijono9c461142008-07-10 22:41:20 +00001201
Benny Prijono55040452008-07-21 18:20:57 +00001202 def add_buddy(self, uri, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001203 """Add new buddy.
1204
1205 Keyword argument:
Benny Prijono55040452008-07-21 18:20:57 +00001206 uri -- SIP URI of the buddy
1207 cb -- BuddyCallback instance to be installed to the newly
1208 created Buddy object. If this callback is not specified
1209 (i.e. None is given), it must be installed later using
1210 buddy.set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001211
1212 Return:
1213 Buddy object
1214 """
Benny Prijono55040452008-07-21 18:20:57 +00001215 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001216 buddy_cfg = _pjsua.buddy_config_default()
1217 buddy_cfg.uri = uri
1218 buddy_cfg.subscribe = False
1219 err, buddy_id = _pjsua.buddy_add(buddy_cfg)
Benny Prijono55040452008-07-21 18:20:57 +00001220 self._lib()._err_check("add_buddy()", self, err)
1221 buddy = Buddy(self._lib(), buddy_id, self, cb)
1222 return buddy
Benny Prijono9c461142008-07-10 22:41:20 +00001223
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001224 def pres_notify(self, pres_obj, state, reason="", hdr_list=None):
1225 """Send NOTIFY to inform account presence status or to terminate
1226 server side presence subscription.
1227
1228 Keyword arguments:
1229 pres_obj -- The subscription object from on_incoming_subscribe()
1230 callback
1231 state -- Subscription state, from SubscriptionState
1232 reason -- Optional reason phrase.
1233 hdr_list -- Optional header list.
1234 """
Benny Prijono55040452008-07-21 18:20:57 +00001235 lck = self._lib().auto_lock()
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001236 _pjsua.acc_pres_notify(self._id, pres_obj, state, reason,
1237 Lib._create_msg_data(hdr_list))
Benny Prijono2d1a94b2009-08-22 11:41:49 +00001238
1239 def send_pager(self, uri, text, im_id=0, content_type="text/plain", \
1240 hdr_list=None):
1241 """Send instant message to arbitrary URI.
1242
1243 Keyword arguments:
1244 text -- Instant message to be sent
1245 uri -- URI to send the Instant Message to.
1246 im_id -- Optional instant message ID to identify this
1247 instant message when delivery status callback
1248 is called.
1249 content_type -- MIME type identifying the instant message
1250 hdr_list -- Optional list of headers to be sent with the
1251 request.
1252
1253 """
1254 lck = self._lib().auto_lock()
1255 err = _pjsua.im_send(self._id, uri, \
1256 content_type, text, \
1257 Lib._create_msg_data(hdr_list), \
1258 im_id)
1259 self._lib()._err_check("send_pager()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001260
1261class CallCallback:
1262 """Class to receive event notification from Call objects.
1263
1264 Use Call.set_callback() method to install instance of this callback
1265 class to receive event notifications from the call object.
Benny Prijonob85ba652008-07-11 00:55:22 +00001266
1267 Member documentation:
1268
1269 call -- the Call object.
1270
Benny Prijono9c461142008-07-10 22:41:20 +00001271 """
1272 call = None
1273
Benny Prijono55040452008-07-21 18:20:57 +00001274 def __init__(self, call=None):
1275 self._set_call(call)
1276
1277 def __del__(self):
1278 pass
1279
1280 def _set_call(self, call):
1281 if call:
1282 self.call = weakref.proxy(call)
1283 else:
1284 self.call = None
Benny Prijono9c461142008-07-10 22:41:20 +00001285
1286 def on_state(self):
1287 """Notification that the call's state has changed.
1288
1289 """
1290 pass
1291
1292 def on_media_state(self):
1293 """Notification that the call's media state has changed.
1294
1295 """
1296 pass
1297
1298 def on_dtmf_digit(self, digits):
1299 """Notification on incoming DTMF digits.
1300
1301 Keyword argument:
1302 digits -- string containing the received digits.
1303
1304 """
1305 pass
1306
1307 def on_transfer_request(self, dst, code):
1308 """Notification that call is being transfered by remote party.
1309
1310 Application can decide to accept/reject transfer request by returning
1311 code greater than or equal to 500. The default behavior is to accept
1312 the transfer by returning 202.
1313
1314 Keyword arguments:
1315 dst -- string containing the destination URI
1316 code -- the suggested status code to return to accept the request.
1317
1318 Return:
1319 the callback should return 202 to accept the request, or 300-699 to
1320 reject the request.
1321
1322 """
1323 return code
1324
1325 def on_transfer_status(self, code, reason, final, cont):
1326 """
1327 Notification about the status of previous call transfer request.
1328
1329 Keyword arguments:
1330 code -- SIP status code to indicate completion status.
1331 text -- SIP status reason phrase.
1332 final -- if True then this is a final status and no further
1333 notifications will be sent for this call transfer
1334 status.
1335 cont -- suggested return value.
1336
1337 Return:
1338 If the callback returns false then no further notification will
1339 be sent for the transfer request for this call.
1340
1341 """
1342 return cont
1343
1344 def on_replace_request(self, code, reason):
1345 """Notification when incoming INVITE with Replaces header is received.
1346
1347 Application may reject the request by returning value greather than
1348 or equal to 500. The default behavior is to accept the request.
1349
1350 Keyword arguments:
1351 code -- default status code to return
1352 reason -- default reason phrase to return
1353
1354 Return:
1355 The callback should return (code, reason) tuple.
1356
1357 """
1358 return code, reason
1359
1360 def on_replaced(self, new_call):
1361 """
1362 Notification that this call will be replaced with new_call.
1363 After this callback is called, this call will be disconnected.
1364
1365 Keyword arguments:
1366 new_call -- the new call that will replace this call.
1367 """
1368 pass
1369
1370 def on_pager(self, mime_type, body):
1371 """
1372 Notification that incoming instant message is received on
1373 this call.
1374
1375 Keyword arguments:
1376 mime_type -- MIME type of the instant message body.
1377 body -- the instant message body.
1378
1379 """
1380 pass
1381
1382 def on_pager_status(self, body, im_id, code, reason):
1383 """
1384 Notification about the delivery status of previously sent
1385 instant message.
1386
1387 Keyword arguments:
1388 body -- message body
1389 im_id -- message ID
1390 code -- SIP status code
1391 reason -- SIP reason phrase
1392
1393 """
1394 pass
1395
1396 def on_typing(self, is_typing):
1397 """
1398 Notification that remote is typing or stop typing.
1399
1400 Keyword arguments:
1401 is_typing -- boolean to indicate whether remote is currently
1402 typing an instant message.
1403
1404 """
1405 pass
1406
1407
1408class CallInfo:
1409 """This structure contains various information about Call.
1410
1411 Application may retrieve this information with Call.info().
Benny Prijonob85ba652008-07-11 00:55:22 +00001412
1413 Member documentation:
1414
1415 role -- CallRole
1416 account -- Account object.
1417 uri -- SIP URI of local account.
1418 contact -- local Contact URI.
1419 remote_uri -- remote SIP URI.
1420 remote_contact -- remote Contact URI
1421 sip_call_id -- call's Call-ID identification
1422 state -- CallState
1423 state_text -- state text.
1424 last_code -- last SIP status code
1425 last_reason -- text phrase for last_code
1426 media_state -- MediaState
1427 media_dir -- MediaDir
1428 conf_slot -- conference slot number for this call.
1429 call_time -- call's connected duration in seconds.
1430 total_time -- total call duration in seconds.
Benny Prijono9c461142008-07-10 22:41:20 +00001431 """
1432 role = CallRole.CALLER
1433 account = None
1434 uri = ""
1435 contact = ""
1436 remote_uri = ""
1437 remote_contact = ""
1438 sip_call_id = ""
1439 state = CallState.NULL
1440 state_text = ""
1441 last_code = 0
1442 last_reason = ""
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001443 media_state = MediaState.NULL
1444 media_dir = MediaDir.NULL
Benny Prijono9c461142008-07-10 22:41:20 +00001445 conf_slot = -1
1446 call_time = 0
1447 total_time = 0
1448
1449 def __init__(self, lib=None, ci=None):
1450 if lib and ci:
1451 self._cvt_from_pjsua(lib, ci)
1452
1453 def _cvt_from_pjsua(self, lib, ci):
1454 self.role = ci.role
1455 self.account = lib._lookup_account(ci.acc_id)
1456 self.uri = ci.local_info
1457 self.contact = ci.local_contact
1458 self.remote_uri = ci.remote_info
1459 self.remote_contact = ci.remote_contact
1460 self.sip_call_id = ci.call_id
1461 self.state = ci.state
1462 self.state_text = ci.state_text
1463 self.last_code = ci.last_status
1464 self.last_reason = ci.last_status_text
1465 self.media_state = ci.media_status
1466 self.media_dir = ci.media_dir
1467 self.conf_slot = ci.conf_slot
Benny Prijono55040452008-07-21 18:20:57 +00001468 self.call_time = ci.connect_duration / 1000
1469 self.total_time = ci.total_duration / 1000
Benny Prijono9c461142008-07-10 22:41:20 +00001470
1471
1472class Call:
1473 """This class represents SIP call.
1474
1475 Application initiates outgoing call with Account.make_call(), and
1476 incoming calls are reported in AccountCallback.on_incoming_call().
1477 """
1478 _id = -1
1479 _cb = None
1480 _lib = None
1481 _obj_name = ""
1482
Benny Prijono55040452008-07-21 18:20:57 +00001483 def __init__(self, lib, call_id, cb=None):
1484 self._lib = weakref.ref(lib)
1485 self.set_callback(cb)
1486 self.attach_to_id(call_id)
1487 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001488
1489 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001490 if self._id != -1:
1491 _pjsua.call_set_user_data(self._id, 0)
1492 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001493
1494 def __str__(self):
1495 return self._obj_name
1496
Benny Prijono55040452008-07-21 18:20:57 +00001497 def attach_to_id(self, call_id):
1498 lck = self._lib().auto_lock()
1499 if self._id != -1:
1500 _pjsua.call_set_user_data(self._id, 0)
1501 self._id = call_id
1502 if self._id != -1:
1503 _pjsua.call_set_user_data(self._id, self)
1504 self._obj_name = "{Call " + self.info().remote_uri + "}"
1505 else:
1506 self._obj_name = "{Call object}"
1507
Benny Prijono9c461142008-07-10 22:41:20 +00001508 def set_callback(self, cb):
1509 """
1510 Set callback object to retrieve event notifications from this call.
1511
1512 Keyword arguments:
1513 cb -- CallCallback instance.
1514 """
1515 if cb:
1516 self._cb = cb
1517 else:
1518 self._cb = CallCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001519 self._cb._set_call(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001520
1521 def info(self):
1522 """
1523 Get the CallInfo.
1524 """
Benny Prijono55040452008-07-21 18:20:57 +00001525 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001526 ci = _pjsua.call_get_info(self._id)
1527 if not ci:
Benny Prijono55040452008-07-21 18:20:57 +00001528 self._lib()._err_check("info", self, -1, "Invalid call")
1529 call_info = CallInfo(self._lib(), ci)
1530 return call_info
Benny Prijono9c461142008-07-10 22:41:20 +00001531
1532 def is_valid(self):
1533 """
1534 Check if this call is still valid.
1535 """
Benny Prijono55040452008-07-21 18:20:57 +00001536 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001537 return _pjsua.call_is_active(self._id)
1538
1539 def dump_status(self, with_media=True, indent="", max_len=1024):
1540 """
1541 Dump the call status.
1542 """
Benny Prijono55040452008-07-21 18:20:57 +00001543 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001544 return _pjsua.call_dump(self._id, with_media, max_len, indent)
1545
1546 def answer(self, code=200, reason="", hdr_list=None):
1547 """
1548 Send provisional or final response to incoming call.
1549
1550 Keyword arguments:
1551 code -- SIP status code.
1552 reason -- Reason phrase. Put empty to send default reason
1553 phrase for the status code.
1554 hdr_list -- Optional list of headers to be sent with the
1555 INVITE response.
1556
1557 """
Benny Prijono55040452008-07-21 18:20:57 +00001558 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001559 err = _pjsua.call_answer(self._id, code, reason,
1560 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001561 self._lib()._err_check("answer()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001562
1563 def hangup(self, code=603, reason="", hdr_list=None):
1564 """
1565 Terminate the call.
1566
1567 Keyword arguments:
1568 code -- SIP status code.
1569 reason -- Reason phrase. Put empty to send default reason
1570 phrase for the status code.
1571 hdr_list -- Optional list of headers to be sent with the
1572 message.
1573
1574 """
Benny Prijono55040452008-07-21 18:20:57 +00001575 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001576 err = _pjsua.call_hangup(self._id, code, reason,
1577 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001578 self._lib()._err_check("hangup()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001579
1580 def hold(self, hdr_list=None):
1581 """
1582 Put the call on hold.
1583
1584 Keyword arguments:
1585 hdr_list -- Optional list of headers to be sent with the
1586 message.
1587 """
Benny Prijono55040452008-07-21 18:20:57 +00001588 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001589 err = _pjsua.call_set_hold(self._id, Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001590 self._lib()._err_check("hold()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001591
1592 def unhold(self, hdr_list=None):
1593 """
1594 Release the call from hold.
1595
1596 Keyword arguments:
1597 hdr_list -- Optional list of headers to be sent with the
1598 message.
1599
1600 """
Benny Prijono55040452008-07-21 18:20:57 +00001601 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001602 err = _pjsua.call_reinvite(self._id, True,
1603 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001604 self._lib()._err_check("unhold()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001605
1606 def reinvite(self, hdr_list=None):
1607 """
1608 Send re-INVITE and optionally offer new codecs to use.
1609
1610 Keyword arguments:
1611 hdr_list -- Optional list of headers to be sent with the
1612 message.
1613
1614 """
Benny Prijono55040452008-07-21 18:20:57 +00001615 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001616 err = _pjsua.call_reinvite(self._id, True,
1617 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001618 self._lib()._err_check("reinvite()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001619
1620 def update(self, hdr_list=None, options=0):
1621 """
1622 Send UPDATE and optionally offer new codecs to use.
1623
1624 Keyword arguments:
1625 hdr_list -- Optional list of headers to be sent with the
1626 message.
1627 options -- Must be zero for now.
1628
1629 """
Benny Prijono55040452008-07-21 18:20:57 +00001630 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001631 err = _pjsua.call_update(self._id, options,
1632 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001633 self._lib()._err_check("update()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001634
1635 def transfer(self, dest_uri, hdr_list=None):
1636 """
1637 Transfer the call to new destination.
1638
1639 Keyword arguments:
1640 dest_uri -- Specify the SIP URI to transfer the call to.
1641 hdr_list -- Optional list of headers to be sent with the
1642 message.
1643
1644 """
Benny Prijono55040452008-07-21 18:20:57 +00001645 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001646 err = _pjsua.call_xfer(self._id, dest_uri,
1647 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001648 self._lib()._err_check("transfer()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001649
1650 def transfer_to_call(self, call, hdr_list=None, options=0):
1651 """
1652 Attended call transfer.
1653
1654 Keyword arguments:
1655 call -- The Call object to transfer call to.
1656 hdr_list -- Optional list of headers to be sent with the
1657 message.
1658 options -- Must be zero for now.
1659
1660 """
Benny Prijono55040452008-07-21 18:20:57 +00001661 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001662 err = _pjsua.call_xfer_replaces(self._id, call._id, options,
1663 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001664 self._lib()._err_check("transfer_to_call()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001665
1666 def dial_dtmf(self, digits):
1667 """
1668 Send DTMF digits with RTP event package.
1669
1670 Keyword arguments:
1671 digits -- DTMF digit string.
1672
1673 """
Benny Prijono55040452008-07-21 18:20:57 +00001674 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001675 err = _pjsua.call_dial_dtmf(self._id, digits)
Benny Prijono55040452008-07-21 18:20:57 +00001676 self._lib()._err_check("dial_dtmf()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001677
1678 def send_request(self, method, hdr_list=None, content_type=None,
1679 body=None):
1680 """
1681 Send arbitrary request to remote call.
1682
1683 This is useful for example to send INFO request. Note that this
1684 function should not be used to send request that will change the
1685 call state such as CANCEL or BYE.
1686
1687 Keyword arguments:
1688 method -- SIP method name.
1689 hdr_list -- Optional header list to be sent with the request.
1690 content_type -- Content type to describe the body, if the body
1691 is present
1692 body -- Optional SIP message body.
1693
1694 """
Benny Prijono55040452008-07-21 18:20:57 +00001695 lck = self._lib().auto_lock()
Benny Prijonof5dd34e2009-08-22 11:47:00 +00001696 if hdr_list or body:
Benny Prijono9c461142008-07-10 22:41:20 +00001697 msg_data = _pjsua.Msg_Data()
1698 if hdr_list:
1699 msg_data.hdr_list = hdr_list
1700 if content_type:
1701 msg_data.content_type = content_type
1702 if body:
1703 msg_data.msg_body = body
1704 else:
1705 msg_data = None
1706
1707 err = _pjsua.call_send_request(self._id, method, msg_data)
Benny Prijono55040452008-07-21 18:20:57 +00001708 self._lib()._err_check("send_request()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001709
Benny Prijono21f871f2008-12-11 11:03:21 +00001710 def send_pager(self, text, im_id=0, content_type="text/plain",
1711 hdr_list=None):
1712 """Send instant message inside a call.
Benny Prijono9c461142008-07-10 22:41:20 +00001713
Benny Prijono21f871f2008-12-11 11:03:21 +00001714 Keyword arguments:
1715 text -- Instant message to be sent
1716 im_id -- Optional instant message ID to identify this
1717 instant message when delivery status callback
1718 is called.
1719 content_type -- MIME type identifying the instant message
1720 hdr_list -- Optional list of headers to be sent with the
1721 request.
1722
1723 """
1724 lck = self._lib().auto_lock()
1725 err = _pjsua.call_send_im(self._id, \
1726 content_type, text, \
1727 Lib._create_msg_data(hdr_list), \
1728 im_id)
1729 self._lib()._err_check("send_pager()", self, err)
1730
1731
Benny Prijono9c461142008-07-10 22:41:20 +00001732class BuddyInfo:
1733 """This class contains information about Buddy. Application may
1734 retrieve this information by calling Buddy.info().
Benny Prijonob85ba652008-07-11 00:55:22 +00001735
1736 Member documentation:
1737
1738 uri -- the Buddy URI.
1739 contact -- the Buddy Contact URI, if available.
1740 online_status -- the presence online status.
1741 online_text -- the presence online status text.
1742 activity -- the PresenceActivity
1743 subscribed -- specify whether buddy's presence status is currently
1744 being subscribed.
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001745 sub_state -- SubscriptionState
1746 sub_term_reason -- The termination reason string of the last presence
1747 subscription to this buddy, if any.
Benny Prijono9c461142008-07-10 22:41:20 +00001748 """
1749 uri = ""
1750 contact = ""
1751 online_status = 0
1752 online_text = ""
1753 activity = PresenceActivity.UNKNOWN
1754 subscribed = False
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001755 sub_state = SubscriptionState.NULL
1756 sub_term_reason = ""
Benny Prijono9c461142008-07-10 22:41:20 +00001757
1758 def __init__(self, pjsua_bi=None):
1759 if pjsua_bi:
1760 self._cvt_from_pjsua(pjsua_bi)
1761
1762 def _cvt_from_pjsua(self, inf):
1763 self.uri = inf.uri
1764 self.contact = inf.contact
1765 self.online_status = inf.status
1766 self.online_text = inf.status_text
1767 self.activity = inf.activity
1768 self.subscribed = inf.monitor_pres
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001769 self.sub_state = inf.sub_state
1770 self.sub_term_reason = inf.sub_term_reason
Benny Prijono9c461142008-07-10 22:41:20 +00001771
1772
1773class BuddyCallback:
1774 """This class can be used to receive notifications about Buddy's
1775 presence status change. Application needs to derive a class from
1776 this class, and register the instance with Buddy.set_callback().
Benny Prijonob85ba652008-07-11 00:55:22 +00001777
1778 Member documentation:
1779
1780 buddy -- the Buddy object.
Benny Prijono9c461142008-07-10 22:41:20 +00001781 """
1782 buddy = None
1783
Benny Prijono55040452008-07-21 18:20:57 +00001784 def __init__(self, buddy=None):
1785 self._set_buddy(buddy)
1786
1787 def _set_buddy(self, buddy):
1788 if buddy:
1789 self.buddy = weakref.proxy(buddy)
1790 else:
1791 self.buddy = None
Benny Prijono9c461142008-07-10 22:41:20 +00001792
1793 def on_state(self):
1794 """
1795 Notification that buddy's presence state has changed. Application
1796 may then retrieve the new status with Buddy.info() function.
1797 """
1798 pass
1799
1800 def on_pager(self, mime_type, body):
1801 """Notification that incoming instant message is received from
1802 this buddy.
1803
1804 Keyword arguments:
1805 mime_type -- MIME type of the instant message body
1806 body -- the instant message body
1807
1808 """
1809 pass
1810
1811 def on_pager_status(self, body, im_id, code, reason):
1812 """Notification about the delivery status of previously sent
1813 instant message.
1814
1815 Keyword arguments:
1816 body -- the message body
1817 im_id -- message ID
1818 code -- SIP status code
1819 reason -- SIP reason phrase
1820
1821 """
1822 pass
1823
1824 def on_typing(self, is_typing):
1825 """Notification that remote is typing or stop typing.
1826
1827 Keyword arguments:
1828 is_typing -- boolean to indicate whether remote is currently
1829 typing an instant message.
1830
1831 """
1832 pass
1833
1834
1835class Buddy:
1836 """A Buddy represents person or remote agent.
1837
1838 This class provides functions to subscribe to buddy's presence and
1839 to send or receive instant messages from the buddy.
1840 """
1841 _id = -1
1842 _lib = None
1843 _cb = None
1844 _obj_name = ""
1845 _acc = None
1846
Benny Prijono55040452008-07-21 18:20:57 +00001847 def __init__(self, lib, id, account, cb):
Benny Prijono9c461142008-07-10 22:41:20 +00001848 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +00001849 self._lib = weakref.ref(lib)
1850 self._acc = weakref.ref(account)
1851 self._obj_name = "{Buddy " + self.info().uri + "}"
1852 self.set_callback(cb)
1853 _pjsua.buddy_set_user_data(self._id, self)
1854 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001855
1856 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001857 if self._id != -1:
1858 _pjsua.buddy_set_user_data(self._id, 0)
1859 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001860
1861 def __str__(self):
1862 return self._obj_name
1863
1864 def info(self):
1865 """
1866 Get buddy info as BuddyInfo.
1867 """
Benny Prijono55040452008-07-21 18:20:57 +00001868 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001869 return BuddyInfo(_pjsua.buddy_get_info(self._id))
1870
1871 def set_callback(self, cb):
1872 """Install callback to receive notifications from this object.
1873
1874 Keyword argument:
1875 cb -- BuddyCallback instance.
1876 """
1877 if cb:
1878 self._cb = cb
1879 else:
1880 self._cb = BuddyCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001881 self._cb._set_buddy(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001882
1883 def subscribe(self):
1884 """
1885 Subscribe to buddy's presence status notification.
1886 """
Benny Prijono55040452008-07-21 18:20:57 +00001887 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001888 err = _pjsua.buddy_subscribe_pres(self._id, True)
Benny Prijono55040452008-07-21 18:20:57 +00001889 self._lib()._err_check("subscribe()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001890
1891 def unsubscribe(self):
1892 """
1893 Unsubscribe from buddy's presence status notification.
1894 """
Benny Prijono55040452008-07-21 18:20:57 +00001895 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001896 err = _pjsua.buddy_subscribe_pres(self._id, False)
Benny Prijono55040452008-07-21 18:20:57 +00001897 self._lib()._err_check("unsubscribe()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001898
1899 def delete(self):
1900 """
1901 Remove this buddy from the buddy list.
1902 """
Benny Prijono55040452008-07-21 18:20:57 +00001903 lck = self._lib().auto_lock()
1904 if self._id != -1:
1905 _pjsua.buddy_set_user_data(self._id, 0)
Benny Prijono9c461142008-07-10 22:41:20 +00001906 err = _pjsua.buddy_del(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001907 self._lib()._err_check("delete()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001908
1909 def send_pager(self, text, im_id=0, content_type="text/plain", \
1910 hdr_list=None):
1911 """Send instant message to remote buddy.
1912
1913 Keyword arguments:
1914 text -- Instant message to be sent
1915 im_id -- Optional instant message ID to identify this
1916 instant message when delivery status callback
1917 is called.
1918 content_type -- MIME type identifying the instant message
1919 hdr_list -- Optional list of headers to be sent with the
1920 request.
1921
1922 """
Benny Prijono55040452008-07-21 18:20:57 +00001923 lck = self._lib().auto_lock()
1924 err = _pjsua.im_send(self._acc()._id, self.info().uri, \
Benny Prijono9c461142008-07-10 22:41:20 +00001925 content_type, text, \
1926 Lib._create_msg_data(hdr_list), \
1927 im_id)
Benny Prijono55040452008-07-21 18:20:57 +00001928 self._lib()._err_check("send_pager()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001929
1930 def send_typing_ind(self, is_typing=True, hdr_list=None):
1931 """Send typing indication to remote buddy.
1932
1933 Keyword argument:
1934 is_typing -- boolean to indicate wheter user is typing.
1935 hdr_list -- Optional list of headers to be sent with the
1936 request.
1937
1938 """
Benny Prijono55040452008-07-21 18:20:57 +00001939 lck = self._lib().auto_lock()
1940 err = _pjsua.im_typing(self._acc()._id, self.info().uri, \
Benny Prijono9c461142008-07-10 22:41:20 +00001941 is_typing, Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001942 self._lib()._err_check("send_typing_ind()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001943
1944
1945
1946# Sound device info
1947class SoundDeviceInfo:
Benny Prijonob85ba652008-07-11 00:55:22 +00001948 """This described the sound device info.
1949
1950 Member documentation:
1951 name -- device name.
1952 input_channels -- number of capture channels supported.
1953 output_channels -- number of playback channels supported.
1954 default_clock_rate -- default sampling rate.
1955 """
Benny Prijono9c461142008-07-10 22:41:20 +00001956 name = ""
1957 input_channels = 0
Benny Prijonob85ba652008-07-11 00:55:22 +00001958 output_channels = 0
Benny Prijono9c461142008-07-10 22:41:20 +00001959 default_clock_rate = 0
1960
1961 def __init__(self, sdi):
1962 self.name = sdi.name
1963 self.input_channels = sdi.input_count
1964 self.output_channels = sdi.output_count
1965 self.default_clock_rate = sdi.default_samples_per_sec
1966
1967
1968# Codec info
1969class CodecInfo:
Benny Prijonob85ba652008-07-11 00:55:22 +00001970 """This describes codec info.
1971
1972 Member documentation:
1973 name -- codec name
1974 priority -- codec priority (0-255)
1975 clock_rate -- clock rate
1976 channel_count -- number of channels
1977 avg_bps -- average bandwidth in bits per second
1978 frm_ptime -- base frame length in milliseconds
1979 ptime -- RTP frame length in milliseconds.
1980 pt -- payload type.
1981 vad_enabled -- specify if Voice Activity Detection is currently
1982 enabled.
1983 plc_enabled -- specify if Packet Lost Concealment is currently
1984 enabled.
1985 """
Benny Prijono9c461142008-07-10 22:41:20 +00001986 name = ""
1987 priority = 0
1988 clock_rate = 0
1989 channel_count = 0
1990 avg_bps = 0
1991 frm_ptime = 0
1992 ptime = 0
1993 pt = 0
1994 vad_enabled = False
1995 plc_enabled = False
1996
1997 def __init__(self, codec_info, codec_param):
Benny Prijono0b627042008-08-18 11:32:13 +00001998 self.name = codec_info.codec_id
Benny Prijono9c461142008-07-10 22:41:20 +00001999 self.priority = codec_info.priority
2000 self.clock_rate = codec_param.info.clock_rate
Benny Prijono0b627042008-08-18 11:32:13 +00002001 self.channel_count = codec_param.info.channel_cnt
Benny Prijono9c461142008-07-10 22:41:20 +00002002 self.avg_bps = codec_param.info.avg_bps
2003 self.frm_ptime = codec_param.info.frm_ptime
2004 self.ptime = codec_param.info.frm_ptime * \
2005 codec_param.setting.frm_per_pkt
2006 self.ptime = codec_param.info.pt
2007 self.vad_enabled = codec_param.setting.vad
2008 self.plc_enabled = codec_param.setting.plc
2009
2010 def _cvt_to_pjsua(self):
2011 ci = _pjsua.Codec_Info()
Benny Prijono0b627042008-08-18 11:32:13 +00002012 ci.codec_id = self.name
Benny Prijono9c461142008-07-10 22:41:20 +00002013 ci.priority = self.priority
2014 return ci
2015
2016
2017# Codec parameter
2018class CodecParameter:
Benny Prijonob85ba652008-07-11 00:55:22 +00002019 """This specifies various parameters that can be configured for codec.
2020
2021 Member documentation:
2022
2023 ptime -- specify the outgoing RTP packet length in milliseconds.
2024 vad_enabled -- specify if VAD should be enabled.
2025 plc_enabled -- specify if PLC should be enabled.
2026 """
Benny Prijono9c461142008-07-10 22:41:20 +00002027 ptime = 0
2028 vad_enabled = False
2029 plc_enabled = False
2030 _codec_param = None
2031
2032 def __init__(self, codec_param):
2033 self.ptime = codec_param.info.frm_ptime * \
2034 codec_param.setting.frm_per_pkt
2035 self.vad_enabled = codec_param.setting.vad
2036 self.plc_enabled = codec_param.setting.plc
2037 self._codec_param = codec_param
2038
2039 def _cvt_to_pjsua(self):
2040 self._codec_param.setting.frm_per_pkt = self.ptime / \
2041 self._codec_param.info.frm_ptime
2042 self._codec_param.setting.vad = self.vad_enabled
2043 self._codec_param.setting.plc = self.plc_enabled
2044 return self._codec_param
2045
2046
Benny Prijono55040452008-07-21 18:20:57 +00002047# Library mutex
2048class _LibMutex:
2049 def __init__(self, lck):
2050 self._lck = lck
2051 self._lck.acquire()
Benny Prijono6ecef072008-07-21 22:46:35 +00002052 #_Trace(('lock acquired',))
Benny Prijono55040452008-07-21 18:20:57 +00002053
2054 def __del__(self):
Benny Prijono6ecef072008-07-21 22:46:35 +00002055 try:
2056 self._lck.release()
2057 #_Trace(('lock released',))
2058 except:
2059 #_Trace(('lock release error',))
2060 pass
Benny Prijono55040452008-07-21 18:20:57 +00002061
2062
Benny Prijono9c461142008-07-10 22:41:20 +00002063# PJSUA Library
2064_lib = None
Benny Prijonofd47c2c2008-07-24 09:00:28 +00002065enable_trace = False
2066
Benny Prijono9c461142008-07-10 22:41:20 +00002067class Lib:
2068 """Library instance.
2069
2070 """
Benny Prijono9c461142008-07-10 22:41:20 +00002071 _quit = False
2072 _has_thread = False
Benny Prijono55040452008-07-21 18:20:57 +00002073 _lock = None
Benny Prijono9c461142008-07-10 22:41:20 +00002074
2075 def __init__(self):
2076 global _lib
2077 if _lib:
2078 raise Error("__init()__", None, -1,
2079 "Library instance already exist")
Benny Prijono55040452008-07-21 18:20:57 +00002080
2081 self._lock = threading.RLock()
Benny Prijono9c461142008-07-10 22:41:20 +00002082 err = _pjsua.create()
2083 self._err_check("_pjsua.create()", None, err)
2084 _lib = self
2085
2086 def __del__(self):
2087 _pjsua.destroy()
Benny Prijono55040452008-07-21 18:20:57 +00002088 del self._lock
Benny Prijono6ecef072008-07-21 22:46:35 +00002089 _Trace(('Lib destroyed',))
Benny Prijono9c461142008-07-10 22:41:20 +00002090
2091 def __str__(self):
2092 return "Lib"
2093
2094 @staticmethod
2095 def instance():
2096 """Return singleton instance of Lib.
2097 """
2098 return _lib
2099
2100 def init(self, ua_cfg=None, log_cfg=None, media_cfg=None):
2101 """
2102 Initialize pjsua with the specified configurations.
2103
2104 Keyword arguments:
2105 ua_cfg -- optional UAConfig instance
2106 log_cfg -- optional LogConfig instance
2107 media_cfg -- optional MediaConfig instance
2108
2109 """
2110 if not ua_cfg: ua_cfg = UAConfig()
2111 if not log_cfg: log_cfg = LogConfig()
2112 if not media_cfg: media_cfg = MediaConfig()
2113
2114 py_ua_cfg = ua_cfg._cvt_to_pjsua()
2115 py_ua_cfg.cb.on_call_state = _cb_on_call_state
2116 py_ua_cfg.cb.on_incoming_call = _cb_on_incoming_call
2117 py_ua_cfg.cb.on_call_media_state = _cb_on_call_media_state
2118 py_ua_cfg.cb.on_dtmf_digit = _cb_on_dtmf_digit
2119 py_ua_cfg.cb.on_call_transfer_request = _cb_on_call_transfer_request
2120 py_ua_cfg.cb.on_call_transfer_status = _cb_on_call_transfer_status
2121 py_ua_cfg.cb.on_call_replace_request = _cb_on_call_replace_request
2122 py_ua_cfg.cb.on_call_replaced = _cb_on_call_replaced
2123 py_ua_cfg.cb.on_reg_state = _cb_on_reg_state
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002124 py_ua_cfg.cb.on_incoming_subscribe = _cb_on_incoming_subscribe
Benny Prijono9c461142008-07-10 22:41:20 +00002125 py_ua_cfg.cb.on_buddy_state = _cb_on_buddy_state
2126 py_ua_cfg.cb.on_pager = _cb_on_pager
2127 py_ua_cfg.cb.on_pager_status = _cb_on_pager_status
2128 py_ua_cfg.cb.on_typing = _cb_on_typing
Benny Prijono6a464882009-10-29 08:16:46 +00002129 py_ua_cfg.cb.on_mwi_info = _cb_on_mwi_info;
Benny Prijono9c461142008-07-10 22:41:20 +00002130
2131 err = _pjsua.init(py_ua_cfg, log_cfg._cvt_to_pjsua(),
Benny Prijono55040452008-07-21 18:20:57 +00002132 media_cfg._cvt_to_pjsua())
Benny Prijono9c461142008-07-10 22:41:20 +00002133 self._err_check("init()", self, err)
2134
2135 def destroy(self):
2136 """Destroy the library, and pjsua."""
2137 global _lib
2138 if self._has_thread:
2139 self._quit = 1
2140 loop = 0
2141 while self._quit != 2 and loop < 400:
Benny Prijono6ecef072008-07-21 22:46:35 +00002142 self.handle_events(5)
Benny Prijono9c461142008-07-10 22:41:20 +00002143 loop = loop + 1
Benny Prijono21f871f2008-12-11 11:03:21 +00002144 time.sleep(0.050)
Benny Prijono9c461142008-07-10 22:41:20 +00002145 _pjsua.destroy()
2146 _lib = None
Benny Prijono55040452008-07-21 18:20:57 +00002147
Benny Prijono9c461142008-07-10 22:41:20 +00002148 def start(self, with_thread=True):
2149 """Start the library.
2150
2151 Keyword argument:
2152 with_thread -- specify whether the module should create worker
2153 thread.
2154
2155 """
Benny Prijono6ecef072008-07-21 22:46:35 +00002156 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002157 err = _pjsua.start()
2158 self._err_check("start()", self, err)
2159 self._has_thread = with_thread
2160 if self._has_thread:
2161 thread.start_new(_worker_thread_main, (0,))
2162
2163 def handle_events(self, timeout=50):
2164 """Poll the events from underlying pjsua library.
2165
2166 Application must poll the stack periodically if worker thread
2167 is disable when starting the library.
2168
2169 Keyword argument:
2170 timeout -- in milliseconds.
2171
2172 """
Benny Prijono55040452008-07-21 18:20:57 +00002173 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002174 return _pjsua.handle_events(timeout)
2175
Benny Prijonod8cd6b92008-12-11 11:18:33 +00002176 def thread_register(self, name):
2177 """Register external threads (threads that are not created by PJSIP,
2178 such as threads that are created by Python API) to PJSIP.
2179
2180 The call must be made from the new thread before calling any pjlib
2181 functions.
2182
2183 Keyword arguments:
2184 name -- Non descriptive name for the thread
2185 """
2186 dummy = 1
2187 err = _pjsua.thread_register(name, dummy)
2188 self._err_check("thread_register()", self, err)
2189
Benny Prijono9c461142008-07-10 22:41:20 +00002190 def verify_sip_url(self, sip_url):
2191 """Verify that the specified string is a valid URI.
2192
2193 Keyword argument:
2194 sip_url -- the URL string.
2195
2196 Return:
2197 0 is the the URI is valid, otherwise the appropriate error
2198 code is returned.
2199
2200 """
Benny Prijono55040452008-07-21 18:20:57 +00002201 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002202 return _pjsua.verify_sip_url(sip_url)
2203
2204 def create_transport(self, type, cfg=None):
2205 """Create SIP transport instance of the specified type.
2206
2207 Keyword arguments:
2208 type -- transport type from TransportType constant.
2209 cfg -- TransportConfig instance
2210
2211 Return:
2212 Transport object
2213
2214 """
Benny Prijono55040452008-07-21 18:20:57 +00002215 lck = self.auto_lock()
Benny Prijonofd47c2c2008-07-24 09:00:28 +00002216 if not cfg: cfg=TransportConfig()
Benny Prijono9c461142008-07-10 22:41:20 +00002217 err, tp_id = _pjsua.transport_create(type, cfg._cvt_to_pjsua())
2218 self._err_check("create_transport()", self, err)
2219 return Transport(self, tp_id)
2220
Benny Prijono55040452008-07-21 18:20:57 +00002221 def create_account(self, acc_config, set_default=True, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00002222 """
2223 Create a new local pjsua account using the specified configuration.
2224
2225 Keyword arguments:
2226 acc_config -- AccountConfig
2227 set_default -- boolean to specify whether to use this as the
2228 default account.
Benny Prijono55040452008-07-21 18:20:57 +00002229 cb -- AccountCallback instance.
Benny Prijono9c461142008-07-10 22:41:20 +00002230
2231 Return:
2232 Account instance
2233
2234 """
Benny Prijono55040452008-07-21 18:20:57 +00002235 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002236 err, acc_id = _pjsua.acc_add(acc_config._cvt_to_pjsua(), set_default)
2237 self._err_check("create_account()", self, err)
Benny Prijono55040452008-07-21 18:20:57 +00002238 return Account(self, acc_id, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00002239
Benny Prijono55040452008-07-21 18:20:57 +00002240 def create_account_for_transport(self, transport, set_default=True,
2241 cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00002242 """Create a new local pjsua transport for the specified transport.
2243
2244 Keyword arguments:
2245 transport -- the Transport instance.
2246 set_default -- boolean to specify whether to use this as the
2247 default account.
Benny Prijono55040452008-07-21 18:20:57 +00002248 cb -- AccountCallback instance.
Benny Prijono9c461142008-07-10 22:41:20 +00002249
2250 Return:
2251 Account instance
2252
2253 """
Benny Prijono55040452008-07-21 18:20:57 +00002254 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002255 err, acc_id = _pjsua.acc_add_local(transport._id, set_default)
2256 self._err_check("create_account_for_transport()", self, err)
Benny Prijono55040452008-07-21 18:20:57 +00002257 return Account(self, acc_id, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00002258
2259 def hangup_all(self):
2260 """Hangup all calls.
2261
2262 """
Benny Prijono55040452008-07-21 18:20:57 +00002263 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002264 _pjsua.call_hangup_all()
2265
2266 # Sound device API
2267
2268 def enum_snd_dev(self):
2269 """Enumerate sound devices in the system.
2270
2271 Return:
Benny Prijono288d4bd2008-07-19 15:40:21 +00002272 list of SoundDeviceInfo. The index of the element specifies
Benny Prijono9c461142008-07-10 22:41:20 +00002273 the device ID for the device.
2274 """
Benny Prijono55040452008-07-21 18:20:57 +00002275 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002276 sdi_list = _pjsua.enum_snd_devs()
Benny Prijono9c461142008-07-10 22:41:20 +00002277 info = []
Benny Prijono288d4bd2008-07-19 15:40:21 +00002278 for sdi in sdi_list:
Benny Prijono9c461142008-07-10 22:41:20 +00002279 info.append(SoundDeviceInfo(sdi))
2280 return info
2281
2282 def get_snd_dev(self):
2283 """Get the device IDs of current sound devices used by pjsua.
2284
2285 Return:
2286 (capture_dev_id, playback_dev_id) tuple
2287 """
Benny Prijono55040452008-07-21 18:20:57 +00002288 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002289 return _pjsua.get_snd_dev()
2290
2291 def set_snd_dev(self, capture_dev, playback_dev):
2292 """Change the current sound devices.
2293
2294 Keyword arguments:
2295 capture_dev -- the device ID of capture device to be used
2296 playback_dev -- the device ID of playback device to be used.
2297
2298 """
Benny Prijono55040452008-07-21 18:20:57 +00002299 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002300 err = _pjsua.set_snd_dev(capture_dev, playback_dev)
2301 self._err_check("set_current_sound_devices()", self, err)
2302
2303 def set_null_snd_dev(self):
2304 """Disable the sound devices. This is useful if the system
2305 does not have sound device installed.
2306
2307 """
Benny Prijono55040452008-07-21 18:20:57 +00002308 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002309 err = _pjsua.set_null_snd_dev()
2310 self._err_check("set_null_snd_dev()", self, err)
2311
2312
2313 # Conference bridge
2314
2315 def conf_get_max_ports(self):
2316 """Get the conference bridge capacity.
2317
2318 Return:
2319 conference bridge capacity.
2320
2321 """
Benny Prijono55040452008-07-21 18:20:57 +00002322 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002323 return _pjsua.conf_get_max_ports()
2324
2325 def conf_connect(self, src_slot, dst_slot):
2326 """Establish unidirectional media flow from souce to sink.
2327
2328 One source may transmit to multiple destinations/sink. And if
2329 multiple sources are transmitting to the same sink, the media
2330 will be mixed together. Source and sink may refer to the same ID,
2331 effectively looping the media.
2332
2333 If bidirectional media flow is desired, application needs to call
2334 this function twice, with the second one having the arguments
2335 reversed.
2336
2337 Keyword arguments:
2338 src_slot -- integer to identify the conference slot number of
2339 the source/transmitter.
2340 dst_slot -- integer to identify the conference slot number of
2341 the destination/receiver.
2342
2343 """
Benny Prijono55040452008-07-21 18:20:57 +00002344 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002345 err = _pjsua.conf_connect(src_slot, dst_slot)
2346 self._err_check("conf_connect()", self, err)
2347
2348 def conf_disconnect(self, src_slot, dst_slot):
2349 """Disconnect media flow from the source to destination port.
2350
2351 Keyword arguments:
2352 src_slot -- integer to identify the conference slot number of
2353 the source/transmitter.
2354 dst_slot -- integer to identify the conference slot number of
2355 the destination/receiver.
2356
2357 """
Benny Prijono55040452008-07-21 18:20:57 +00002358 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002359 err = _pjsua.conf_disconnect(src_slot, dst_slot)
2360 self._err_check("conf_disconnect()", self, err)
2361
Benny Prijono288d4bd2008-07-19 15:40:21 +00002362 def conf_set_tx_level(self, slot, level):
2363 """Adjust the signal level to be transmitted from the bridge to
2364 the specified port by making it louder or quieter.
2365
2366 Keyword arguments:
2367 slot -- integer to identify the conference slot number.
2368 level -- Signal level adjustment. Value 1.0 means no level
2369 adjustment, while value 0 means to mute the port.
2370 """
Benny Prijono55040452008-07-21 18:20:57 +00002371 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002372 err = _pjsua.conf_set_tx_level(slot, level)
2373 self._err_check("conf_set_tx_level()", self, err)
2374
2375 def conf_set_rx_level(self, slot, level):
2376 """Adjust the signal level to be received from the specified port
2377 (to the bridge) by making it louder or quieter.
2378
2379 Keyword arguments:
2380 slot -- integer to identify the conference slot number.
2381 level -- Signal level adjustment. Value 1.0 means no level
2382 adjustment, while value 0 means to mute the port.
2383 """
Benny Prijono55040452008-07-21 18:20:57 +00002384 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002385 err = _pjsua.conf_set_rx_level(slot, level)
2386 self._err_check("conf_set_rx_level()", self, err)
2387
2388 def conf_get_signal_level(self, slot):
2389 """Get last signal level transmitted to or received from the
2390 specified port. The signal levels are float values from 0.0 to 1.0,
2391 with 0.0 indicates no signal, and 1.0 indicates the loudest signal
2392 level.
2393
2394 Keyword arguments:
2395 slot -- integer to identify the conference slot number.
2396
2397 Return value:
2398 (tx_level, rx_level) tuple.
2399 """
Benny Prijono55040452008-07-21 18:20:57 +00002400 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002401 err, tx_level, rx_level = _pjsua.conf_get_signal_level(slot)
2402 self._err_check("conf_get_signal_level()", self, err)
2403 return (tx_level, rx_level)
2404
2405
2406
Benny Prijono9c461142008-07-10 22:41:20 +00002407 # Codecs API
2408
2409 def enum_codecs(self):
2410 """Return list of codecs supported by pjsua.
2411
2412 Return:
Benny Prijono288d4bd2008-07-19 15:40:21 +00002413 list of CodecInfo
Benny Prijono9c461142008-07-10 22:41:20 +00002414
2415 """
Benny Prijono55040452008-07-21 18:20:57 +00002416 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002417 ci_list = _pjsua.enum_codecs()
Benny Prijono9c461142008-07-10 22:41:20 +00002418 codec_info = []
Benny Prijono288d4bd2008-07-19 15:40:21 +00002419 for ci in ci_list:
Benny Prijono0b627042008-08-18 11:32:13 +00002420 cp = _pjsua.codec_get_param(ci.codec_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002421 if cp:
2422 codec_info.append(CodecInfo(ci, cp))
2423 return codec_info
2424
2425 def set_codec_priority(self, name, priority):
2426 """Change the codec priority.
2427
2428 Keyword arguments:
2429 name -- Codec name
2430 priority -- Codec priority, which range is 0-255.
2431
2432 """
Benny Prijono55040452008-07-21 18:20:57 +00002433 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002434 err = _pjsua.codec_set_priority(name, priority)
2435 self._err_check("set_codec_priority()", self, err)
2436
2437 def get_codec_parameter(self, name):
2438 """Get codec parameter for the specified codec.
2439
2440 Keyword arguments:
2441 name -- codec name.
2442
2443 """
Benny Prijono55040452008-07-21 18:20:57 +00002444 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002445 cp = _pjsua.codec_get_param(name)
2446 if not cp:
2447 self._err_check("get_codec_parameter()", self, -1,
2448 "Invalid codec name")
2449 return CodecParameter(cp)
2450
2451 def set_codec_parameter(self, name, param):
2452 """Modify codec parameter for the specified codec.
2453
2454 Keyword arguments:
2455 name -- codec name
2456 param -- codec parameter.
2457
2458 """
Benny Prijono55040452008-07-21 18:20:57 +00002459 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002460 err = _pjsua.codec_set_param(name, param._cvt_to_pjsua())
2461 self._err_check("set_codec_parameter()", self, err)
2462
2463 # WAV playback and recording
2464
2465 def create_player(self, filename, loop=False):
2466 """Create WAV file player.
2467
2468 Keyword arguments
2469 filename -- WAV file name
Benny Prijono288d4bd2008-07-19 15:40:21 +00002470 loop -- boolean to specify whether playback should
2471 automatically restart upon EOF
Benny Prijono9c461142008-07-10 22:41:20 +00002472 Return:
2473 WAV player ID
2474
2475 """
Benny Prijono55040452008-07-21 18:20:57 +00002476 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002477 opt = 0
2478 if not loop:
2479 opt = opt + 1
2480 err, player_id = _pjsua.player_create(filename, opt)
2481 self._err_check("create_player()", self, err)
2482 return player_id
2483
2484 def player_get_slot(self, player_id):
2485 """Get the conference port ID for the specified player.
2486
2487 Keyword arguments:
2488 player_id -- the WAV player ID
2489
2490 Return:
2491 Conference slot number for the player
2492
2493 """
Benny Prijono55040452008-07-21 18:20:57 +00002494 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002495 slot = _pjsua.player_get_conf_port(player_id)
Benny Prijono940bd3e2008-07-11 09:14:40 +00002496 if slot < 0:
2497 self._err_check("player_get_slot()", self, -1,
2498 "Invalid player id")
Benny Prijono9c461142008-07-10 22:41:20 +00002499 return slot
2500
2501 def player_set_pos(self, player_id, pos):
2502 """Set WAV playback position.
2503
2504 Keyword arguments:
2505 player_id -- WAV player ID
2506 pos -- playback position, in samples
2507
2508 """
Benny Prijono55040452008-07-21 18:20:57 +00002509 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002510 err = _pjsua.player_set_pos(player_id, pos)
2511 self._err_check("player_set_pos()", self, err)
2512
2513 def player_destroy(self, player_id):
2514 """Destroy the WAV player.
2515
2516 Keyword arguments:
2517 player_id -- the WAV player ID.
2518
2519 """
Benny Prijono55040452008-07-21 18:20:57 +00002520 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002521 err = _pjsua.player_destroy(player_id)
2522 self._err_check("player_destroy()", self, err)
2523
Benny Prijono288d4bd2008-07-19 15:40:21 +00002524 def create_playlist(self, filelist, label="playlist", loop=True):
2525 """Create WAV playlist.
2526
2527 Keyword arguments:
2528 filelist -- List of WAV file names.
2529 label -- Optional name to be assigned to the playlist
2530 object (useful for logging)
2531 loop -- boolean to specify whether playback should
2532 automatically restart upon EOF
2533
2534 Return:
2535 playlist_id
2536 """
Benny Prijono55040452008-07-21 18:20:57 +00002537 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002538 opt = 0
2539 if not loop:
2540 opt = opt + 1
2541 err, playlist_id = _pjsua.playlist_create(label, filelist, opt)
2542 self._err_check("create_playlist()", self, err)
2543 return playlist_id
2544
2545 def playlist_get_slot(self, playlist_id):
2546 """Get the conference port ID for the specified playlist.
2547
2548 Keyword arguments:
2549 playlist_id -- the WAV playlist ID
2550
2551 Return:
2552 Conference slot number for the playlist
2553
2554 """
Benny Prijono55040452008-07-21 18:20:57 +00002555 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002556 slot = _pjsua.player_get_conf_port(playlist_id)
2557 if slot < 0:
2558 self._err_check("playlist_get_slot()", self, -1,
2559 "Invalid playlist id")
2560 return slot
2561
2562 def playlist_destroy(self, playlist_id):
2563 """Destroy the WAV playlist.
2564
2565 Keyword arguments:
2566 playlist_id -- the WAV playlist ID.
2567
2568 """
Benny Prijono55040452008-07-21 18:20:57 +00002569 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002570 err = _pjsua.player_destroy(playlist_id)
2571 self._err_check("playlist_destroy()", self, err)
2572
Benny Prijono9c461142008-07-10 22:41:20 +00002573 def create_recorder(self, filename):
2574 """Create WAV file recorder.
2575
2576 Keyword arguments
2577 filename -- WAV file name
2578
2579 Return:
2580 WAV recorder ID
2581
2582 """
Benny Prijono55040452008-07-21 18:20:57 +00002583 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002584 err, rec_id = _pjsua.recorder_create(filename, 0, None, -1, 0)
2585 self._err_check("create_recorder()", self, err)
2586 return rec_id
2587
2588 def recorder_get_slot(self, rec_id):
2589 """Get the conference port ID for the specified recorder.
2590
2591 Keyword arguments:
2592 rec_id -- the WAV recorder ID
2593
2594 Return:
2595 Conference slot number for the recorder
2596
2597 """
Benny Prijono55040452008-07-21 18:20:57 +00002598 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002599 slot = _pjsua.recorder_get_conf_port(rec_id)
Benny Prijono940bd3e2008-07-11 09:14:40 +00002600 if slot < 1:
2601 self._err_check("recorder_get_slot()", self, -1,
2602 "Invalid recorder id")
Benny Prijono9c461142008-07-10 22:41:20 +00002603 return slot
2604
2605 def recorder_destroy(self, rec_id):
2606 """Destroy the WAV recorder.
2607
2608 Keyword arguments:
2609 rec_id -- the WAV recorder ID.
2610
2611 """
Benny Prijono55040452008-07-21 18:20:57 +00002612 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002613 err = _pjsua.recorder_destroy(rec_id)
2614 self._err_check("recorder_destroy()", self, err)
2615
2616
2617 # Internal functions
2618
2619 @staticmethod
2620 def strerror(err):
2621 return _pjsua.strerror(err)
2622
2623 def _err_check(self, op_name, obj, err_code, err_msg=""):
2624 if err_code != 0:
2625 raise Error(op_name, obj, err_code, err_msg)
2626
2627 @staticmethod
2628 def _create_msg_data(hdr_list):
2629 if not hdr_list:
2630 return None
2631 msg_data = _pjsua.Msg_Data()
2632 msg_data.hdr_list = hdr_list
2633 return msg_data
2634
Benny Prijono55040452008-07-21 18:20:57 +00002635 def auto_lock(self):
2636 return _LibMutex(self._lock)
2637
Benny Prijono9c461142008-07-10 22:41:20 +00002638 # Internal dictionary manipulation for calls, accounts, and buddies
2639
Benny Prijono9c461142008-07-10 22:41:20 +00002640 def _lookup_call(self, call_id):
Benny Prijono55040452008-07-21 18:20:57 +00002641 return _pjsua.call_get_user_data(call_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002642
2643 def _lookup_account(self, acc_id):
Benny Prijono55040452008-07-21 18:20:57 +00002644 return _pjsua.acc_get_user_data(acc_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002645
2646 def _lookup_buddy(self, buddy_id, uri=None):
Benny Prijono55040452008-07-21 18:20:57 +00002647 if buddy_id != -1:
2648 buddy = _pjsua.buddy_get_user_data(buddy_id)
2649 elif uri:
2650 buddy_id = _pjsua.buddy_find(uri)
2651 if buddy_id != -1:
2652 buddy = _pjsua.buddy_get_user_data(buddy_id)
2653 else:
2654 buddy = None
2655 else:
2656 buddy = None
2657
Benny Prijono9c461142008-07-10 22:41:20 +00002658 return buddy
2659
Benny Prijono9c461142008-07-10 22:41:20 +00002660 # Account allbacks
2661
2662 def _cb_on_reg_state(self, acc_id):
2663 acc = self._lookup_account(acc_id)
2664 if acc:
2665 acc._cb.on_reg_state()
2666
Benny Prijono55040452008-07-21 18:20:57 +00002667 def _cb_on_incoming_subscribe(self, acc_id, buddy_id, from_uri,
2668 contact_uri, pres_obj):
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002669 acc = self._lookup_account(acc_id)
2670 if acc:
2671 buddy = self._lookup_buddy(buddy_id)
Benny Prijono55040452008-07-21 18:20:57 +00002672 return acc._cb.on_incoming_subscribe(buddy, from_uri, contact_uri,
2673 pres_obj)
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002674 else:
2675 return (404, None)
2676
Benny Prijono9c461142008-07-10 22:41:20 +00002677 def _cb_on_incoming_call(self, acc_id, call_id, rdata):
2678 acc = self._lookup_account(acc_id)
2679 if acc:
2680 acc._cb.on_incoming_call( Call(self, call_id) )
2681 else:
2682 _pjsua.call_hangup(call_id, 603, None, None)
2683
2684 # Call callbacks
2685
2686 def _cb_on_call_state(self, call_id):
2687 call = self._lookup_call(call_id)
2688 if call:
Benny Prijono55040452008-07-21 18:20:57 +00002689 if call._id == -1:
2690 call.attach_to_id(call_id)
2691 done = (call.info().state == CallState.DISCONNECTED)
Benny Prijono9c461142008-07-10 22:41:20 +00002692 call._cb.on_state()
Benny Prijono55040452008-07-21 18:20:57 +00002693 if done:
2694 _pjsua.call_set_user_data(call_id, 0)
2695 else:
2696 pass
Benny Prijono9c461142008-07-10 22:41:20 +00002697
2698 def _cb_on_call_media_state(self, call_id):
2699 call = self._lookup_call(call_id)
2700 if call:
2701 call._cb.on_media_state()
2702
2703 def _cb_on_dtmf_digit(self, call_id, digits):
2704 call = self._lookup_call(call_id)
2705 if call:
2706 call._cb.on_dtmf_digit(digits)
2707
2708 def _cb_on_call_transfer_request(self, call_id, dst, code):
2709 call = self._lookup_call(call_id)
2710 if call:
2711 return call._cb.on_transfer_request(dst, code)
2712 else:
2713 return 603
2714
2715 def _cb_on_call_transfer_status(self, call_id, code, text, final, cont):
2716 call = self._lookup_call(call_id)
2717 if call:
2718 return call._cb.on_transfer_status(code, text, final, cont)
2719 else:
2720 return cont
2721
2722 def _cb_on_call_replace_request(self, call_id, rdata, code, reason):
2723 call = self._lookup_call(call_id)
2724 if call:
2725 return call._cb.on_replace_request(code, reason)
2726 else:
2727 return code, reason
2728
2729 def _cb_on_call_replaced(self, old_call_id, new_call_id):
2730 old_call = self._lookup_call(old_call_id)
2731 new_call = self._lookup_call(new_call_id)
2732 if old_call and new_call:
2733 old_call._cb.on_replaced(new_call)
2734
2735 def _cb_on_pager(self, call_id, from_uri, to_uri, contact, mime_type,
2736 body, acc_id):
2737 call = None
Benny Prijono21f871f2008-12-11 11:03:21 +00002738 if call_id != -1:
Benny Prijono9c461142008-07-10 22:41:20 +00002739 call = self._lookup_call(call_id)
2740 if call:
2741 call._cb.on_pager(mime_type, body)
2742 else:
2743 acc = self._lookup_account(acc_id)
2744 buddy = self._lookup_buddy(-1, from_uri)
2745 if buddy:
2746 buddy._cb.on_pager(mime_type, body)
2747 else:
2748 acc._cb.on_pager(from_uri, contact, mime_type, body)
2749
2750 def _cb_on_pager_status(self, call_id, to_uri, body, user_data,
2751 code, reason, acc_id):
2752 call = None
Benny Prijono21f871f2008-12-11 11:03:21 +00002753 if call_id != -1:
Benny Prijono9c461142008-07-10 22:41:20 +00002754 call = self._lookup_call(call_id)
2755 if call:
2756 call._cb.on_pager_status(body, user_data, code, reason)
2757 else:
2758 acc = self._lookup_account(acc_id)
2759 buddy = self._lookup_buddy(-1, to_uri)
2760 if buddy:
2761 buddy._cb.on_pager_status(body, user_data, code, reason)
2762 else:
2763 acc._cb.on_pager_status(to_uri, body, user_data, code, reason)
2764
2765 def _cb_on_typing(self, call_id, from_uri, to_uri, contact, is_typing,
2766 acc_id):
2767 call = None
Benny Prijono21f871f2008-12-11 11:03:21 +00002768 if call_id != -1:
Benny Prijono9c461142008-07-10 22:41:20 +00002769 call = self._lookup_call(call_id)
2770 if call:
2771 call._cb.on_typing(is_typing)
2772 else:
2773 acc = self._lookup_account(acc_id)
2774 buddy = self._lookup_buddy(-1, from_uri)
2775 if buddy:
2776 buddy._cb.on_typing(is_typing)
2777 else:
2778 acc._cb.on_typing(from_uri, contact, is_typing)
2779
Benny Prijono6a464882009-10-29 08:16:46 +00002780 def _cb_on_mwi_info(self, acc_id, body):
2781 acc = self._lookup_account(acc_id)
2782 if acc:
2783 return acc._cb.on_mwi_info(body)
2784
Benny Prijono9c461142008-07-10 22:41:20 +00002785 def _cb_on_buddy_state(self, buddy_id):
2786 buddy = self._lookup_buddy(buddy_id)
2787 if buddy:
2788 buddy._cb.on_state()
2789
Benny Prijono9c461142008-07-10 22:41:20 +00002790#
2791# Internal
2792#
2793
2794def _cb_on_call_state(call_id, e):
2795 _lib._cb_on_call_state(call_id)
2796
2797def _cb_on_incoming_call(acc_id, call_id, rdata):
2798 _lib._cb_on_incoming_call(acc_id, call_id, rdata)
2799
2800def _cb_on_call_media_state(call_id):
2801 _lib._cb_on_call_media_state(call_id)
2802
2803def _cb_on_dtmf_digit(call_id, digits):
2804 _lib._cb_on_dtmf_digit(call_id, digits)
2805
2806def _cb_on_call_transfer_request(call_id, dst, code):
2807 return _lib._cb_on_call_transfer_request(call_id, dst, code)
2808
2809def _cb_on_call_transfer_status(call_id, code, reason, final, cont):
2810 return _lib._cb_on_call_transfer_status(call_id, code, reason,
2811 final, cont)
2812def _cb_on_call_replace_request(call_id, rdata, code, reason):
2813 return _lib._cb_on_call_replace_request(call_id, rdata, code, reason)
2814
2815def _cb_on_call_replaced(old_call_id, new_call_id):
2816 _lib._cb_on_call_replaced(old_call_id, new_call_id)
2817
2818def _cb_on_reg_state(acc_id):
2819 _lib._cb_on_reg_state(acc_id)
2820
Benny Prijono55040452008-07-21 18:20:57 +00002821def _cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, contact_uri, pres):
2822 return _lib._cb_on_incoming_subscribe(acc_id, buddy_id, from_uri,
2823 contact_uri, pres)
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002824
Benny Prijono9c461142008-07-10 22:41:20 +00002825def _cb_on_buddy_state(buddy_id):
2826 _lib._cb_on_buddy_state(buddy_id)
2827
2828def _cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id):
2829 _lib._cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id)
2830
2831def _cb_on_pager_status(call_id, to, body, user_data, status, reason, acc_id):
2832 _lib._cb_on_pager_status(call_id, to, body, user_data,
2833 status, reason, acc_id)
2834
2835def _cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id):
2836 _lib._cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id)
2837
Benny Prijono6a464882009-10-29 08:16:46 +00002838def _cb_on_mwi_info(acc_id, body):
2839 _lib._cb_on_mwi_info(acc_id, body)
Benny Prijono9c461142008-07-10 22:41:20 +00002840
2841# Worker thread
2842def _worker_thread_main(arg):
2843 global _lib
Benny Prijono6ecef072008-07-21 22:46:35 +00002844 _Trace(('worker thread started..',))
Benny Prijono9c461142008-07-10 22:41:20 +00002845 thread_desc = 0;
2846 err = _pjsua.thread_register("python worker", thread_desc)
2847 _lib._err_check("thread_register()", _lib, err)
Benny Prijono55040452008-07-21 18:20:57 +00002848 while _lib and _lib._quit == 0:
Benny Prijono6ecef072008-07-21 22:46:35 +00002849 _lib.handle_events(1)
2850 time.sleep(0.050)
Benny Prijono55040452008-07-21 18:20:57 +00002851 if _lib:
2852 _lib._quit = 2
Benny Prijono6ecef072008-07-21 22:46:35 +00002853 _Trace(('worker thread exited..',))
Benny Prijono9c461142008-07-10 22:41:20 +00002854
Benny Prijono55040452008-07-21 18:20:57 +00002855def _Trace(args):
Benny Prijonofd47c2c2008-07-24 09:00:28 +00002856 global enable_trace
2857 if enable_trace:
Benny Prijono55040452008-07-21 18:20:57 +00002858 print "** ",
2859 for arg in args:
2860 print arg,
2861 print " **"
Benny Prijono6ecef072008-07-21 22:46:35 +00002862