blob: 8c573695568685e47f5153bea3d4001b4b451d66 [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
996
997
998class Account:
999 """This describes SIP account class.
1000
1001 PJSUA accounts provide identity (or identities) of the user who is
1002 currently using the application. In SIP terms, the identity is used
1003 as the From header in outgoing requests.
1004
1005 Account may or may not have client registration associated with it.
1006 An account is also associated with route set and some authentication
1007 credentials, which are used when sending SIP request messages using
1008 the account. An account also has presence's online status, which
1009 will be reported to remote peer when they subscribe to the account's
1010 presence, or which is published to a presence server if presence
1011 publication is enabled for the account.
1012
1013 Account is created with Lib.create_account(). At least one account
1014 MUST be created. If no user association is required, application can
1015 create a userless account by calling Lib.create_account_for_transport().
1016 A userless account identifies local endpoint instead of a particular
1017 user, and it correspond with a particular transport instance.
1018
1019 Also one account must be set as the default account, which is used as
1020 the account to use when PJSUA fails to match a request with any other
1021 accounts.
1022
1023 """
1024 _id = -1
1025 _lib = None
1026 _cb = AccountCallback(None)
1027 _obj_name = ""
1028
Benny Prijono55040452008-07-21 18:20:57 +00001029 def __init__(self, lib, id, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001030 """Construct this class. This is normally called by Lib class and
1031 not by application.
1032
1033 Keyword arguments:
1034 lib -- the Lib instance.
1035 id -- the pjsua account ID.
Benny Prijono55040452008-07-21 18:20:57 +00001036 cb -- AccountCallback instance to receive events from this Account.
1037 If callback is not specified here, it must be set later
1038 using set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001039 """
Benny Prijono9c461142008-07-10 22:41:20 +00001040 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +00001041 self._lib = weakref.ref(lib)
1042 self._obj_name = "{Account " + self.info().uri + "}"
1043 self.set_callback(cb)
1044 _pjsua.acc_set_user_data(self._id, self)
1045 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001046
1047 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001048 if self._id != -1:
1049 _pjsua.acc_set_user_data(self._id, 0)
1050 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001051
1052 def __str__(self):
1053 return self._obj_name
1054
1055 def info(self):
1056 """Retrieve AccountInfo for this account.
1057 """
Benny Prijono55040452008-07-21 18:20:57 +00001058 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001059 ai = _pjsua.acc_get_info(self._id)
1060 if ai==None:
Benny Prijono55040452008-07-21 18:20:57 +00001061 self._lib()._err_check("info()", self, -1, "Invalid account")
Benny Prijono9c461142008-07-10 22:41:20 +00001062 return AccountInfo(ai)
1063
1064 def is_valid(self):
1065 """
1066 Check if this account is still valid.
1067
1068 """
Benny Prijono55040452008-07-21 18:20:57 +00001069 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001070 return _pjsua.acc_is_valid(self._id)
1071
1072 def set_callback(self, cb):
1073 """Register callback to receive notifications from this object.
1074
1075 Keyword argument:
1076 cb -- AccountCallback instance.
1077
1078 """
1079 if cb:
1080 self._cb = cb
1081 else:
1082 self._cb = AccountCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001083 self._cb._set_account(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001084
1085 def set_default(self):
1086 """ Set this account as default account to send outgoing requests
1087 and as the account to receive incoming requests when more exact
1088 matching criteria fails.
1089 """
Benny Prijono55040452008-07-21 18:20:57 +00001090 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001091 err = _pjsua.acc_set_default(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001092 self._lib()._err_check("set_default()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001093
1094 def is_default(self):
1095 """ Check if this account is the default account.
1096
1097 """
Benny Prijono55040452008-07-21 18:20:57 +00001098 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001099 def_id = _pjsua.acc_get_default()
1100 return self.is_valid() and def_id==self._id
1101
1102 def delete(self):
1103 """ Delete this account.
1104
1105 """
Benny Prijono55040452008-07-21 18:20:57 +00001106 lck = self._lib().auto_lock()
1107 err = _pjsua.acc_set_user_data(self._id, 0)
1108 self._lib()._err_check("delete()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001109 err = _pjsua.acc_del(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001110 self._lib()._err_check("delete()", self, err)
1111 self._id = -1
Benny Prijono9c461142008-07-10 22:41:20 +00001112
1113 def set_basic_status(self, is_online):
1114 """ Set basic presence status of this account.
1115
1116 Keyword argument:
1117 is_online -- boolean to indicate basic presence availability.
1118
1119 """
Benny Prijono55040452008-07-21 18:20:57 +00001120 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001121 err = _pjsua.acc_set_online_status(self._id, is_online)
Benny Prijono55040452008-07-21 18:20:57 +00001122 self._lib()._err_check("set_basic_status()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001123
1124 def set_presence_status(self, is_online,
1125 activity=PresenceActivity.UNKNOWN,
1126 pres_text="", rpid_id=""):
1127 """ Set presence status of this account.
1128
1129 Keyword arguments:
1130 is_online -- boolean to indicate basic presence availability
1131 activity -- value from PresenceActivity
1132 pres_text -- optional string to convey additional information about
1133 the activity (such as "On the phone")
1134 rpid_id -- optional string to be placed as RPID ID.
1135
1136 """
Benny Prijono55040452008-07-21 18:20:57 +00001137 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001138 err = _pjsua.acc_set_online_status2(self._id, is_online, activity,
1139 pres_text, rpid_id)
Benny Prijono55040452008-07-21 18:20:57 +00001140 self._lib()._err_check("set_presence_status()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001141
1142 def set_registration(self, renew):
1143 """Manually renew registration or unregister from the server.
1144
1145 Keyword argument:
1146 renew -- boolean to indicate whether registration is renewed.
1147 Setting this value for False will trigger unregistration.
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_registration(self._id, renew)
Benny Prijono55040452008-07-21 18:20:57 +00001152 self._lib()._err_check("set_registration()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001153
1154 def set_transport(self, transport):
1155 """Set this account to only use the specified transport to send
1156 outgoing requests.
1157
1158 Keyword argument:
1159 transport -- Transport object.
1160
1161 """
Benny Prijono55040452008-07-21 18:20:57 +00001162 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001163 err = _pjsua.acc_set_transport(self._id, transport._id)
Benny Prijono55040452008-07-21 18:20:57 +00001164 self._lib()._err_check("set_transport()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001165
Benny Prijono55040452008-07-21 18:20:57 +00001166 def make_call(self, dst_uri, cb=None, hdr_list=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001167 """Make outgoing call to the specified URI.
1168
1169 Keyword arguments:
1170 dst_uri -- Destination SIP URI.
Benny Prijono55040452008-07-21 18:20:57 +00001171 cb -- CallCallback instance to be installed to the newly
1172 created Call object. If this CallCallback is not
1173 specified (i.e. None is given), it must be installed
1174 later using call.set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001175 hdr_list -- Optional list of headers to be sent with outgoing
1176 INVITE
1177
Benny Prijono55040452008-07-21 18:20:57 +00001178 Return:
1179 Call instance.
Benny Prijono9c461142008-07-10 22:41:20 +00001180 """
Benny Prijono55040452008-07-21 18:20:57 +00001181 lck = self._lib().auto_lock()
1182 call = Call(self._lib(), -1, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00001183 err, cid = _pjsua.call_make_call(self._id, dst_uri, 0,
Benny Prijono55040452008-07-21 18:20:57 +00001184 call, Lib._create_msg_data(hdr_list))
1185 self._lib()._err_check("make_call()", self, err)
1186 call.attach_to_id(cid)
1187 return call
Benny Prijono9c461142008-07-10 22:41:20 +00001188
Benny Prijono55040452008-07-21 18:20:57 +00001189 def add_buddy(self, uri, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00001190 """Add new buddy.
1191
1192 Keyword argument:
Benny Prijono55040452008-07-21 18:20:57 +00001193 uri -- SIP URI of the buddy
1194 cb -- BuddyCallback instance to be installed to the newly
1195 created Buddy object. If this callback is not specified
1196 (i.e. None is given), it must be installed later using
1197 buddy.set_callback().
Benny Prijono9c461142008-07-10 22:41:20 +00001198
1199 Return:
1200 Buddy object
1201 """
Benny Prijono55040452008-07-21 18:20:57 +00001202 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001203 buddy_cfg = _pjsua.buddy_config_default()
1204 buddy_cfg.uri = uri
1205 buddy_cfg.subscribe = False
1206 err, buddy_id = _pjsua.buddy_add(buddy_cfg)
Benny Prijono55040452008-07-21 18:20:57 +00001207 self._lib()._err_check("add_buddy()", self, err)
1208 buddy = Buddy(self._lib(), buddy_id, self, cb)
1209 return buddy
Benny Prijono9c461142008-07-10 22:41:20 +00001210
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001211 def pres_notify(self, pres_obj, state, reason="", hdr_list=None):
1212 """Send NOTIFY to inform account presence status or to terminate
1213 server side presence subscription.
1214
1215 Keyword arguments:
1216 pres_obj -- The subscription object from on_incoming_subscribe()
1217 callback
1218 state -- Subscription state, from SubscriptionState
1219 reason -- Optional reason phrase.
1220 hdr_list -- Optional header list.
1221 """
Benny Prijono55040452008-07-21 18:20:57 +00001222 lck = self._lib().auto_lock()
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001223 _pjsua.acc_pres_notify(self._id, pres_obj, state, reason,
1224 Lib._create_msg_data(hdr_list))
Benny Prijono9c461142008-07-10 22:41:20 +00001225
1226class CallCallback:
1227 """Class to receive event notification from Call objects.
1228
1229 Use Call.set_callback() method to install instance of this callback
1230 class to receive event notifications from the call object.
Benny Prijonob85ba652008-07-11 00:55:22 +00001231
1232 Member documentation:
1233
1234 call -- the Call object.
1235
Benny Prijono9c461142008-07-10 22:41:20 +00001236 """
1237 call = None
1238
Benny Prijono55040452008-07-21 18:20:57 +00001239 def __init__(self, call=None):
1240 self._set_call(call)
1241
1242 def __del__(self):
1243 pass
1244
1245 def _set_call(self, call):
1246 if call:
1247 self.call = weakref.proxy(call)
1248 else:
1249 self.call = None
Benny Prijono9c461142008-07-10 22:41:20 +00001250
1251 def on_state(self):
1252 """Notification that the call's state has changed.
1253
1254 """
1255 pass
1256
1257 def on_media_state(self):
1258 """Notification that the call's media state has changed.
1259
1260 """
1261 pass
1262
1263 def on_dtmf_digit(self, digits):
1264 """Notification on incoming DTMF digits.
1265
1266 Keyword argument:
1267 digits -- string containing the received digits.
1268
1269 """
1270 pass
1271
1272 def on_transfer_request(self, dst, code):
1273 """Notification that call is being transfered by remote party.
1274
1275 Application can decide to accept/reject transfer request by returning
1276 code greater than or equal to 500. The default behavior is to accept
1277 the transfer by returning 202.
1278
1279 Keyword arguments:
1280 dst -- string containing the destination URI
1281 code -- the suggested status code to return to accept the request.
1282
1283 Return:
1284 the callback should return 202 to accept the request, or 300-699 to
1285 reject the request.
1286
1287 """
1288 return code
1289
1290 def on_transfer_status(self, code, reason, final, cont):
1291 """
1292 Notification about the status of previous call transfer request.
1293
1294 Keyword arguments:
1295 code -- SIP status code to indicate completion status.
1296 text -- SIP status reason phrase.
1297 final -- if True then this is a final status and no further
1298 notifications will be sent for this call transfer
1299 status.
1300 cont -- suggested return value.
1301
1302 Return:
1303 If the callback returns false then no further notification will
1304 be sent for the transfer request for this call.
1305
1306 """
1307 return cont
1308
1309 def on_replace_request(self, code, reason):
1310 """Notification when incoming INVITE with Replaces header is received.
1311
1312 Application may reject the request by returning value greather than
1313 or equal to 500. The default behavior is to accept the request.
1314
1315 Keyword arguments:
1316 code -- default status code to return
1317 reason -- default reason phrase to return
1318
1319 Return:
1320 The callback should return (code, reason) tuple.
1321
1322 """
1323 return code, reason
1324
1325 def on_replaced(self, new_call):
1326 """
1327 Notification that this call will be replaced with new_call.
1328 After this callback is called, this call will be disconnected.
1329
1330 Keyword arguments:
1331 new_call -- the new call that will replace this call.
1332 """
1333 pass
1334
1335 def on_pager(self, mime_type, body):
1336 """
1337 Notification that incoming instant message is received on
1338 this call.
1339
1340 Keyword arguments:
1341 mime_type -- MIME type of the instant message body.
1342 body -- the instant message body.
1343
1344 """
1345 pass
1346
1347 def on_pager_status(self, body, im_id, code, reason):
1348 """
1349 Notification about the delivery status of previously sent
1350 instant message.
1351
1352 Keyword arguments:
1353 body -- message body
1354 im_id -- message ID
1355 code -- SIP status code
1356 reason -- SIP reason phrase
1357
1358 """
1359 pass
1360
1361 def on_typing(self, is_typing):
1362 """
1363 Notification that remote is typing or stop typing.
1364
1365 Keyword arguments:
1366 is_typing -- boolean to indicate whether remote is currently
1367 typing an instant message.
1368
1369 """
1370 pass
1371
1372
1373class CallInfo:
1374 """This structure contains various information about Call.
1375
1376 Application may retrieve this information with Call.info().
Benny Prijonob85ba652008-07-11 00:55:22 +00001377
1378 Member documentation:
1379
1380 role -- CallRole
1381 account -- Account object.
1382 uri -- SIP URI of local account.
1383 contact -- local Contact URI.
1384 remote_uri -- remote SIP URI.
1385 remote_contact -- remote Contact URI
1386 sip_call_id -- call's Call-ID identification
1387 state -- CallState
1388 state_text -- state text.
1389 last_code -- last SIP status code
1390 last_reason -- text phrase for last_code
1391 media_state -- MediaState
1392 media_dir -- MediaDir
1393 conf_slot -- conference slot number for this call.
1394 call_time -- call's connected duration in seconds.
1395 total_time -- total call duration in seconds.
Benny Prijono9c461142008-07-10 22:41:20 +00001396 """
1397 role = CallRole.CALLER
1398 account = None
1399 uri = ""
1400 contact = ""
1401 remote_uri = ""
1402 remote_contact = ""
1403 sip_call_id = ""
1404 state = CallState.NULL
1405 state_text = ""
1406 last_code = 0
1407 last_reason = ""
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001408 media_state = MediaState.NULL
1409 media_dir = MediaDir.NULL
Benny Prijono9c461142008-07-10 22:41:20 +00001410 conf_slot = -1
1411 call_time = 0
1412 total_time = 0
1413
1414 def __init__(self, lib=None, ci=None):
1415 if lib and ci:
1416 self._cvt_from_pjsua(lib, ci)
1417
1418 def _cvt_from_pjsua(self, lib, ci):
1419 self.role = ci.role
1420 self.account = lib._lookup_account(ci.acc_id)
1421 self.uri = ci.local_info
1422 self.contact = ci.local_contact
1423 self.remote_uri = ci.remote_info
1424 self.remote_contact = ci.remote_contact
1425 self.sip_call_id = ci.call_id
1426 self.state = ci.state
1427 self.state_text = ci.state_text
1428 self.last_code = ci.last_status
1429 self.last_reason = ci.last_status_text
1430 self.media_state = ci.media_status
1431 self.media_dir = ci.media_dir
1432 self.conf_slot = ci.conf_slot
Benny Prijono55040452008-07-21 18:20:57 +00001433 self.call_time = ci.connect_duration / 1000
1434 self.total_time = ci.total_duration / 1000
Benny Prijono9c461142008-07-10 22:41:20 +00001435
1436
1437class Call:
1438 """This class represents SIP call.
1439
1440 Application initiates outgoing call with Account.make_call(), and
1441 incoming calls are reported in AccountCallback.on_incoming_call().
1442 """
1443 _id = -1
1444 _cb = None
1445 _lib = None
1446 _obj_name = ""
1447
Benny Prijono55040452008-07-21 18:20:57 +00001448 def __init__(self, lib, call_id, cb=None):
1449 self._lib = weakref.ref(lib)
1450 self.set_callback(cb)
1451 self.attach_to_id(call_id)
1452 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001453
1454 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001455 if self._id != -1:
1456 _pjsua.call_set_user_data(self._id, 0)
1457 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001458
1459 def __str__(self):
1460 return self._obj_name
1461
Benny Prijono55040452008-07-21 18:20:57 +00001462 def attach_to_id(self, call_id):
1463 lck = self._lib().auto_lock()
1464 if self._id != -1:
1465 _pjsua.call_set_user_data(self._id, 0)
1466 self._id = call_id
1467 if self._id != -1:
1468 _pjsua.call_set_user_data(self._id, self)
1469 self._obj_name = "{Call " + self.info().remote_uri + "}"
1470 else:
1471 self._obj_name = "{Call object}"
1472
Benny Prijono9c461142008-07-10 22:41:20 +00001473 def set_callback(self, cb):
1474 """
1475 Set callback object to retrieve event notifications from this call.
1476
1477 Keyword arguments:
1478 cb -- CallCallback instance.
1479 """
1480 if cb:
1481 self._cb = cb
1482 else:
1483 self._cb = CallCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001484 self._cb._set_call(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001485
1486 def info(self):
1487 """
1488 Get the CallInfo.
1489 """
Benny Prijono55040452008-07-21 18:20:57 +00001490 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001491 ci = _pjsua.call_get_info(self._id)
1492 if not ci:
Benny Prijono55040452008-07-21 18:20:57 +00001493 self._lib()._err_check("info", self, -1, "Invalid call")
1494 call_info = CallInfo(self._lib(), ci)
1495 return call_info
Benny Prijono9c461142008-07-10 22:41:20 +00001496
1497 def is_valid(self):
1498 """
1499 Check if this call is still valid.
1500 """
Benny Prijono55040452008-07-21 18:20:57 +00001501 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001502 return _pjsua.call_is_active(self._id)
1503
1504 def dump_status(self, with_media=True, indent="", max_len=1024):
1505 """
1506 Dump the call status.
1507 """
Benny Prijono55040452008-07-21 18:20:57 +00001508 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001509 return _pjsua.call_dump(self._id, with_media, max_len, indent)
1510
1511 def answer(self, code=200, reason="", hdr_list=None):
1512 """
1513 Send provisional or final response to incoming call.
1514
1515 Keyword arguments:
1516 code -- SIP status code.
1517 reason -- Reason phrase. Put empty to send default reason
1518 phrase for the status code.
1519 hdr_list -- Optional list of headers to be sent with the
1520 INVITE response.
1521
1522 """
Benny Prijono55040452008-07-21 18:20:57 +00001523 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001524 err = _pjsua.call_answer(self._id, code, reason,
1525 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001526 self._lib()._err_check("answer()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001527
1528 def hangup(self, code=603, reason="", hdr_list=None):
1529 """
1530 Terminate the call.
1531
1532 Keyword arguments:
1533 code -- SIP status code.
1534 reason -- Reason phrase. Put empty to send default reason
1535 phrase for the status code.
1536 hdr_list -- Optional list of headers to be sent with the
1537 message.
1538
1539 """
Benny Prijono55040452008-07-21 18:20:57 +00001540 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001541 err = _pjsua.call_hangup(self._id, code, reason,
1542 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001543 self._lib()._err_check("hangup()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001544
1545 def hold(self, hdr_list=None):
1546 """
1547 Put the call on hold.
1548
1549 Keyword arguments:
1550 hdr_list -- Optional list of headers to be sent with the
1551 message.
1552 """
Benny Prijono55040452008-07-21 18:20:57 +00001553 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001554 err = _pjsua.call_set_hold(self._id, Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001555 self._lib()._err_check("hold()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001556
1557 def unhold(self, hdr_list=None):
1558 """
1559 Release the call from hold.
1560
1561 Keyword arguments:
1562 hdr_list -- Optional list of headers to be sent with the
1563 message.
1564
1565 """
Benny Prijono55040452008-07-21 18:20:57 +00001566 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001567 err = _pjsua.call_reinvite(self._id, True,
1568 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001569 self._lib()._err_check("unhold()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001570
1571 def reinvite(self, hdr_list=None):
1572 """
1573 Send re-INVITE and optionally offer new codecs to use.
1574
1575 Keyword arguments:
1576 hdr_list -- Optional list of headers to be sent with the
1577 message.
1578
1579 """
Benny Prijono55040452008-07-21 18:20:57 +00001580 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001581 err = _pjsua.call_reinvite(self._id, True,
1582 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001583 self._lib()._err_check("reinvite()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001584
1585 def update(self, hdr_list=None, options=0):
1586 """
1587 Send UPDATE and optionally offer new codecs to use.
1588
1589 Keyword arguments:
1590 hdr_list -- Optional list of headers to be sent with the
1591 message.
1592 options -- Must be zero for now.
1593
1594 """
Benny Prijono55040452008-07-21 18:20:57 +00001595 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001596 err = _pjsua.call_update(self._id, options,
1597 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001598 self._lib()._err_check("update()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001599
1600 def transfer(self, dest_uri, hdr_list=None):
1601 """
1602 Transfer the call to new destination.
1603
1604 Keyword arguments:
1605 dest_uri -- Specify the SIP URI to transfer the call to.
1606 hdr_list -- Optional list of headers to be sent with the
1607 message.
1608
1609 """
Benny Prijono55040452008-07-21 18:20:57 +00001610 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001611 err = _pjsua.call_xfer(self._id, dest_uri,
1612 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001613 self._lib()._err_check("transfer()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001614
1615 def transfer_to_call(self, call, hdr_list=None, options=0):
1616 """
1617 Attended call transfer.
1618
1619 Keyword arguments:
1620 call -- The Call object to transfer call to.
1621 hdr_list -- Optional list of headers to be sent with the
1622 message.
1623 options -- Must be zero for now.
1624
1625 """
Benny Prijono55040452008-07-21 18:20:57 +00001626 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001627 err = _pjsua.call_xfer_replaces(self._id, call._id, options,
1628 Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001629 self._lib()._err_check("transfer_to_call()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001630
1631 def dial_dtmf(self, digits):
1632 """
1633 Send DTMF digits with RTP event package.
1634
1635 Keyword arguments:
1636 digits -- DTMF digit string.
1637
1638 """
Benny Prijono55040452008-07-21 18:20:57 +00001639 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001640 err = _pjsua.call_dial_dtmf(self._id, digits)
Benny Prijono55040452008-07-21 18:20:57 +00001641 self._lib()._err_check("dial_dtmf()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001642
1643 def send_request(self, method, hdr_list=None, content_type=None,
1644 body=None):
1645 """
1646 Send arbitrary request to remote call.
1647
1648 This is useful for example to send INFO request. Note that this
1649 function should not be used to send request that will change the
1650 call state such as CANCEL or BYE.
1651
1652 Keyword arguments:
1653 method -- SIP method name.
1654 hdr_list -- Optional header list to be sent with the request.
1655 content_type -- Content type to describe the body, if the body
1656 is present
1657 body -- Optional SIP message body.
1658
1659 """
Benny Prijono55040452008-07-21 18:20:57 +00001660 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001661 if hdr_list and body:
1662 msg_data = _pjsua.Msg_Data()
1663 if hdr_list:
1664 msg_data.hdr_list = hdr_list
1665 if content_type:
1666 msg_data.content_type = content_type
1667 if body:
1668 msg_data.msg_body = body
1669 else:
1670 msg_data = None
1671
1672 err = _pjsua.call_send_request(self._id, method, msg_data)
Benny Prijono55040452008-07-21 18:20:57 +00001673 self._lib()._err_check("send_request()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001674
1675
1676class BuddyInfo:
1677 """This class contains information about Buddy. Application may
1678 retrieve this information by calling Buddy.info().
Benny Prijonob85ba652008-07-11 00:55:22 +00001679
1680 Member documentation:
1681
1682 uri -- the Buddy URI.
1683 contact -- the Buddy Contact URI, if available.
1684 online_status -- the presence online status.
1685 online_text -- the presence online status text.
1686 activity -- the PresenceActivity
1687 subscribed -- specify whether buddy's presence status is currently
1688 being subscribed.
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001689 sub_state -- SubscriptionState
1690 sub_term_reason -- The termination reason string of the last presence
1691 subscription to this buddy, if any.
Benny Prijono9c461142008-07-10 22:41:20 +00001692 """
1693 uri = ""
1694 contact = ""
1695 online_status = 0
1696 online_text = ""
1697 activity = PresenceActivity.UNKNOWN
1698 subscribed = False
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001699 sub_state = SubscriptionState.NULL
1700 sub_term_reason = ""
Benny Prijono9c461142008-07-10 22:41:20 +00001701
1702 def __init__(self, pjsua_bi=None):
1703 if pjsua_bi:
1704 self._cvt_from_pjsua(pjsua_bi)
1705
1706 def _cvt_from_pjsua(self, inf):
1707 self.uri = inf.uri
1708 self.contact = inf.contact
1709 self.online_status = inf.status
1710 self.online_text = inf.status_text
1711 self.activity = inf.activity
1712 self.subscribed = inf.monitor_pres
Benny Prijonoe6787ec2008-07-18 23:00:56 +00001713 self.sub_state = inf.sub_state
1714 self.sub_term_reason = inf.sub_term_reason
Benny Prijono9c461142008-07-10 22:41:20 +00001715
1716
1717class BuddyCallback:
1718 """This class can be used to receive notifications about Buddy's
1719 presence status change. Application needs to derive a class from
1720 this class, and register the instance with Buddy.set_callback().
Benny Prijonob85ba652008-07-11 00:55:22 +00001721
1722 Member documentation:
1723
1724 buddy -- the Buddy object.
Benny Prijono9c461142008-07-10 22:41:20 +00001725 """
1726 buddy = None
1727
Benny Prijono55040452008-07-21 18:20:57 +00001728 def __init__(self, buddy=None):
1729 self._set_buddy(buddy)
1730
1731 def _set_buddy(self, buddy):
1732 if buddy:
1733 self.buddy = weakref.proxy(buddy)
1734 else:
1735 self.buddy = None
Benny Prijono9c461142008-07-10 22:41:20 +00001736
1737 def on_state(self):
1738 """
1739 Notification that buddy's presence state has changed. Application
1740 may then retrieve the new status with Buddy.info() function.
1741 """
1742 pass
1743
1744 def on_pager(self, mime_type, body):
1745 """Notification that incoming instant message is received from
1746 this buddy.
1747
1748 Keyword arguments:
1749 mime_type -- MIME type of the instant message body
1750 body -- the instant message body
1751
1752 """
1753 pass
1754
1755 def on_pager_status(self, body, im_id, code, reason):
1756 """Notification about the delivery status of previously sent
1757 instant message.
1758
1759 Keyword arguments:
1760 body -- the message body
1761 im_id -- message ID
1762 code -- SIP status code
1763 reason -- SIP reason phrase
1764
1765 """
1766 pass
1767
1768 def on_typing(self, is_typing):
1769 """Notification that remote is typing or stop typing.
1770
1771 Keyword arguments:
1772 is_typing -- boolean to indicate whether remote is currently
1773 typing an instant message.
1774
1775 """
1776 pass
1777
1778
1779class Buddy:
1780 """A Buddy represents person or remote agent.
1781
1782 This class provides functions to subscribe to buddy's presence and
1783 to send or receive instant messages from the buddy.
1784 """
1785 _id = -1
1786 _lib = None
1787 _cb = None
1788 _obj_name = ""
1789 _acc = None
1790
Benny Prijono55040452008-07-21 18:20:57 +00001791 def __init__(self, lib, id, account, cb):
Benny Prijono9c461142008-07-10 22:41:20 +00001792 self._id = id
Benny Prijono55040452008-07-21 18:20:57 +00001793 self._lib = weakref.ref(lib)
1794 self._acc = weakref.ref(account)
1795 self._obj_name = "{Buddy " + self.info().uri + "}"
1796 self.set_callback(cb)
1797 _pjsua.buddy_set_user_data(self._id, self)
1798 _Trace((self, 'created'))
Benny Prijono9c461142008-07-10 22:41:20 +00001799
1800 def __del__(self):
Benny Prijono55040452008-07-21 18:20:57 +00001801 if self._id != -1:
1802 _pjsua.buddy_set_user_data(self._id, 0)
1803 _Trace((self, 'destroyed'))
Benny Prijono9c461142008-07-10 22:41:20 +00001804
1805 def __str__(self):
1806 return self._obj_name
1807
1808 def info(self):
1809 """
1810 Get buddy info as BuddyInfo.
1811 """
Benny Prijono55040452008-07-21 18:20:57 +00001812 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001813 return BuddyInfo(_pjsua.buddy_get_info(self._id))
1814
1815 def set_callback(self, cb):
1816 """Install callback to receive notifications from this object.
1817
1818 Keyword argument:
1819 cb -- BuddyCallback instance.
1820 """
1821 if cb:
1822 self._cb = cb
1823 else:
1824 self._cb = BuddyCallback(self)
Benny Prijono55040452008-07-21 18:20:57 +00001825 self._cb._set_buddy(self)
Benny Prijono9c461142008-07-10 22:41:20 +00001826
1827 def subscribe(self):
1828 """
1829 Subscribe to buddy's presence status notification.
1830 """
Benny Prijono55040452008-07-21 18:20:57 +00001831 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001832 err = _pjsua.buddy_subscribe_pres(self._id, True)
Benny Prijono55040452008-07-21 18:20:57 +00001833 self._lib()._err_check("subscribe()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001834
1835 def unsubscribe(self):
1836 """
1837 Unsubscribe from buddy's presence status notification.
1838 """
Benny Prijono55040452008-07-21 18:20:57 +00001839 lck = self._lib().auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00001840 err = _pjsua.buddy_subscribe_pres(self._id, False)
Benny Prijono55040452008-07-21 18:20:57 +00001841 self._lib()._err_check("unsubscribe()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001842
1843 def delete(self):
1844 """
1845 Remove this buddy from the buddy list.
1846 """
Benny Prijono55040452008-07-21 18:20:57 +00001847 lck = self._lib().auto_lock()
1848 if self._id != -1:
1849 _pjsua.buddy_set_user_data(self._id, 0)
Benny Prijono9c461142008-07-10 22:41:20 +00001850 err = _pjsua.buddy_del(self._id)
Benny Prijono55040452008-07-21 18:20:57 +00001851 self._lib()._err_check("delete()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001852
1853 def send_pager(self, text, im_id=0, content_type="text/plain", \
1854 hdr_list=None):
1855 """Send instant message to remote buddy.
1856
1857 Keyword arguments:
1858 text -- Instant message to be sent
1859 im_id -- Optional instant message ID to identify this
1860 instant message when delivery status callback
1861 is called.
1862 content_type -- MIME type identifying the instant message
1863 hdr_list -- Optional list of headers to be sent with the
1864 request.
1865
1866 """
Benny Prijono55040452008-07-21 18:20:57 +00001867 lck = self._lib().auto_lock()
1868 err = _pjsua.im_send(self._acc()._id, self.info().uri, \
Benny Prijono9c461142008-07-10 22:41:20 +00001869 content_type, text, \
1870 Lib._create_msg_data(hdr_list), \
1871 im_id)
Benny Prijono55040452008-07-21 18:20:57 +00001872 self._lib()._err_check("send_pager()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001873
1874 def send_typing_ind(self, is_typing=True, hdr_list=None):
1875 """Send typing indication to remote buddy.
1876
1877 Keyword argument:
1878 is_typing -- boolean to indicate wheter user is typing.
1879 hdr_list -- Optional list of headers to be sent with the
1880 request.
1881
1882 """
Benny Prijono55040452008-07-21 18:20:57 +00001883 lck = self._lib().auto_lock()
1884 err = _pjsua.im_typing(self._acc()._id, self.info().uri, \
Benny Prijono9c461142008-07-10 22:41:20 +00001885 is_typing, Lib._create_msg_data(hdr_list))
Benny Prijono55040452008-07-21 18:20:57 +00001886 self._lib()._err_check("send_typing_ind()", self, err)
Benny Prijono9c461142008-07-10 22:41:20 +00001887
1888
1889
1890# Sound device info
1891class SoundDeviceInfo:
Benny Prijonob85ba652008-07-11 00:55:22 +00001892 """This described the sound device info.
1893
1894 Member documentation:
1895 name -- device name.
1896 input_channels -- number of capture channels supported.
1897 output_channels -- number of playback channels supported.
1898 default_clock_rate -- default sampling rate.
1899 """
Benny Prijono9c461142008-07-10 22:41:20 +00001900 name = ""
1901 input_channels = 0
Benny Prijonob85ba652008-07-11 00:55:22 +00001902 output_channels = 0
Benny Prijono9c461142008-07-10 22:41:20 +00001903 default_clock_rate = 0
1904
1905 def __init__(self, sdi):
1906 self.name = sdi.name
1907 self.input_channels = sdi.input_count
1908 self.output_channels = sdi.output_count
1909 self.default_clock_rate = sdi.default_samples_per_sec
1910
1911
1912# Codec info
1913class CodecInfo:
Benny Prijonob85ba652008-07-11 00:55:22 +00001914 """This describes codec info.
1915
1916 Member documentation:
1917 name -- codec name
1918 priority -- codec priority (0-255)
1919 clock_rate -- clock rate
1920 channel_count -- number of channels
1921 avg_bps -- average bandwidth in bits per second
1922 frm_ptime -- base frame length in milliseconds
1923 ptime -- RTP frame length in milliseconds.
1924 pt -- payload type.
1925 vad_enabled -- specify if Voice Activity Detection is currently
1926 enabled.
1927 plc_enabled -- specify if Packet Lost Concealment is currently
1928 enabled.
1929 """
Benny Prijono9c461142008-07-10 22:41:20 +00001930 name = ""
1931 priority = 0
1932 clock_rate = 0
1933 channel_count = 0
1934 avg_bps = 0
1935 frm_ptime = 0
1936 ptime = 0
1937 pt = 0
1938 vad_enabled = False
1939 plc_enabled = False
1940
1941 def __init__(self, codec_info, codec_param):
Benny Prijono0b627042008-08-18 11:32:13 +00001942 self.name = codec_info.codec_id
Benny Prijono9c461142008-07-10 22:41:20 +00001943 self.priority = codec_info.priority
1944 self.clock_rate = codec_param.info.clock_rate
Benny Prijono0b627042008-08-18 11:32:13 +00001945 self.channel_count = codec_param.info.channel_cnt
Benny Prijono9c461142008-07-10 22:41:20 +00001946 self.avg_bps = codec_param.info.avg_bps
1947 self.frm_ptime = codec_param.info.frm_ptime
1948 self.ptime = codec_param.info.frm_ptime * \
1949 codec_param.setting.frm_per_pkt
1950 self.ptime = codec_param.info.pt
1951 self.vad_enabled = codec_param.setting.vad
1952 self.plc_enabled = codec_param.setting.plc
1953
1954 def _cvt_to_pjsua(self):
1955 ci = _pjsua.Codec_Info()
Benny Prijono0b627042008-08-18 11:32:13 +00001956 ci.codec_id = self.name
Benny Prijono9c461142008-07-10 22:41:20 +00001957 ci.priority = self.priority
1958 return ci
1959
1960
1961# Codec parameter
1962class CodecParameter:
Benny Prijonob85ba652008-07-11 00:55:22 +00001963 """This specifies various parameters that can be configured for codec.
1964
1965 Member documentation:
1966
1967 ptime -- specify the outgoing RTP packet length in milliseconds.
1968 vad_enabled -- specify if VAD should be enabled.
1969 plc_enabled -- specify if PLC should be enabled.
1970 """
Benny Prijono9c461142008-07-10 22:41:20 +00001971 ptime = 0
1972 vad_enabled = False
1973 plc_enabled = False
1974 _codec_param = None
1975
1976 def __init__(self, codec_param):
1977 self.ptime = codec_param.info.frm_ptime * \
1978 codec_param.setting.frm_per_pkt
1979 self.vad_enabled = codec_param.setting.vad
1980 self.plc_enabled = codec_param.setting.plc
1981 self._codec_param = codec_param
1982
1983 def _cvt_to_pjsua(self):
1984 self._codec_param.setting.frm_per_pkt = self.ptime / \
1985 self._codec_param.info.frm_ptime
1986 self._codec_param.setting.vad = self.vad_enabled
1987 self._codec_param.setting.plc = self.plc_enabled
1988 return self._codec_param
1989
1990
Benny Prijono55040452008-07-21 18:20:57 +00001991# Library mutex
1992class _LibMutex:
1993 def __init__(self, lck):
1994 self._lck = lck
1995 self._lck.acquire()
Benny Prijono6ecef072008-07-21 22:46:35 +00001996 #_Trace(('lock acquired',))
Benny Prijono55040452008-07-21 18:20:57 +00001997
1998 def __del__(self):
Benny Prijono6ecef072008-07-21 22:46:35 +00001999 try:
2000 self._lck.release()
2001 #_Trace(('lock released',))
2002 except:
2003 #_Trace(('lock release error',))
2004 pass
Benny Prijono55040452008-07-21 18:20:57 +00002005
2006
Benny Prijono9c461142008-07-10 22:41:20 +00002007# PJSUA Library
2008_lib = None
Benny Prijonofd47c2c2008-07-24 09:00:28 +00002009enable_trace = False
2010
Benny Prijono9c461142008-07-10 22:41:20 +00002011class Lib:
2012 """Library instance.
2013
2014 """
Benny Prijono9c461142008-07-10 22:41:20 +00002015 _quit = False
2016 _has_thread = False
Benny Prijono55040452008-07-21 18:20:57 +00002017 _lock = None
Benny Prijono9c461142008-07-10 22:41:20 +00002018
2019 def __init__(self):
2020 global _lib
2021 if _lib:
2022 raise Error("__init()__", None, -1,
2023 "Library instance already exist")
Benny Prijono55040452008-07-21 18:20:57 +00002024
2025 self._lock = threading.RLock()
Benny Prijono9c461142008-07-10 22:41:20 +00002026 err = _pjsua.create()
2027 self._err_check("_pjsua.create()", None, err)
2028 _lib = self
2029
2030 def __del__(self):
2031 _pjsua.destroy()
Benny Prijono55040452008-07-21 18:20:57 +00002032 del self._lock
Benny Prijono6ecef072008-07-21 22:46:35 +00002033 _Trace(('Lib destroyed',))
Benny Prijono9c461142008-07-10 22:41:20 +00002034
2035 def __str__(self):
2036 return "Lib"
2037
2038 @staticmethod
2039 def instance():
2040 """Return singleton instance of Lib.
2041 """
2042 return _lib
2043
2044 def init(self, ua_cfg=None, log_cfg=None, media_cfg=None):
2045 """
2046 Initialize pjsua with the specified configurations.
2047
2048 Keyword arguments:
2049 ua_cfg -- optional UAConfig instance
2050 log_cfg -- optional LogConfig instance
2051 media_cfg -- optional MediaConfig instance
2052
2053 """
2054 if not ua_cfg: ua_cfg = UAConfig()
2055 if not log_cfg: log_cfg = LogConfig()
2056 if not media_cfg: media_cfg = MediaConfig()
2057
2058 py_ua_cfg = ua_cfg._cvt_to_pjsua()
2059 py_ua_cfg.cb.on_call_state = _cb_on_call_state
2060 py_ua_cfg.cb.on_incoming_call = _cb_on_incoming_call
2061 py_ua_cfg.cb.on_call_media_state = _cb_on_call_media_state
2062 py_ua_cfg.cb.on_dtmf_digit = _cb_on_dtmf_digit
2063 py_ua_cfg.cb.on_call_transfer_request = _cb_on_call_transfer_request
2064 py_ua_cfg.cb.on_call_transfer_status = _cb_on_call_transfer_status
2065 py_ua_cfg.cb.on_call_replace_request = _cb_on_call_replace_request
2066 py_ua_cfg.cb.on_call_replaced = _cb_on_call_replaced
2067 py_ua_cfg.cb.on_reg_state = _cb_on_reg_state
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002068 py_ua_cfg.cb.on_incoming_subscribe = _cb_on_incoming_subscribe
Benny Prijono9c461142008-07-10 22:41:20 +00002069 py_ua_cfg.cb.on_buddy_state = _cb_on_buddy_state
2070 py_ua_cfg.cb.on_pager = _cb_on_pager
2071 py_ua_cfg.cb.on_pager_status = _cb_on_pager_status
2072 py_ua_cfg.cb.on_typing = _cb_on_typing
2073
2074 err = _pjsua.init(py_ua_cfg, log_cfg._cvt_to_pjsua(),
Benny Prijono55040452008-07-21 18:20:57 +00002075 media_cfg._cvt_to_pjsua())
Benny Prijono9c461142008-07-10 22:41:20 +00002076 self._err_check("init()", self, err)
2077
2078 def destroy(self):
2079 """Destroy the library, and pjsua."""
2080 global _lib
2081 if self._has_thread:
2082 self._quit = 1
2083 loop = 0
2084 while self._quit != 2 and loop < 400:
Benny Prijono6ecef072008-07-21 22:46:35 +00002085 self.handle_events(5)
Benny Prijono9c461142008-07-10 22:41:20 +00002086 loop = loop + 1
Benny Prijono6ecef072008-07-21 22:46:35 +00002087 time.sleep(0.050)
Benny Prijono9c461142008-07-10 22:41:20 +00002088 _pjsua.destroy()
2089 _lib = None
Benny Prijono55040452008-07-21 18:20:57 +00002090
Benny Prijono9c461142008-07-10 22:41:20 +00002091 def start(self, with_thread=True):
2092 """Start the library.
2093
2094 Keyword argument:
2095 with_thread -- specify whether the module should create worker
2096 thread.
2097
2098 """
Benny Prijono6ecef072008-07-21 22:46:35 +00002099 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002100 err = _pjsua.start()
2101 self._err_check("start()", self, err)
2102 self._has_thread = with_thread
2103 if self._has_thread:
2104 thread.start_new(_worker_thread_main, (0,))
2105
2106 def handle_events(self, timeout=50):
2107 """Poll the events from underlying pjsua library.
2108
2109 Application must poll the stack periodically if worker thread
2110 is disable when starting the library.
2111
2112 Keyword argument:
2113 timeout -- in milliseconds.
2114
2115 """
Benny Prijono55040452008-07-21 18:20:57 +00002116 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002117 return _pjsua.handle_events(timeout)
2118
2119 def verify_sip_url(self, sip_url):
2120 """Verify that the specified string is a valid URI.
2121
2122 Keyword argument:
2123 sip_url -- the URL string.
2124
2125 Return:
2126 0 is the the URI is valid, otherwise the appropriate error
2127 code is returned.
2128
2129 """
Benny Prijono55040452008-07-21 18:20:57 +00002130 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002131 return _pjsua.verify_sip_url(sip_url)
2132
2133 def create_transport(self, type, cfg=None):
2134 """Create SIP transport instance of the specified type.
2135
2136 Keyword arguments:
2137 type -- transport type from TransportType constant.
2138 cfg -- TransportConfig instance
2139
2140 Return:
2141 Transport object
2142
2143 """
Benny Prijono55040452008-07-21 18:20:57 +00002144 lck = self.auto_lock()
Benny Prijonofd47c2c2008-07-24 09:00:28 +00002145 if not cfg: cfg=TransportConfig()
Benny Prijono9c461142008-07-10 22:41:20 +00002146 err, tp_id = _pjsua.transport_create(type, cfg._cvt_to_pjsua())
2147 self._err_check("create_transport()", self, err)
2148 return Transport(self, tp_id)
2149
Benny Prijono55040452008-07-21 18:20:57 +00002150 def create_account(self, acc_config, set_default=True, cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00002151 """
2152 Create a new local pjsua account using the specified configuration.
2153
2154 Keyword arguments:
2155 acc_config -- AccountConfig
2156 set_default -- boolean to specify whether to use this as the
2157 default account.
Benny Prijono55040452008-07-21 18:20:57 +00002158 cb -- AccountCallback instance.
Benny Prijono9c461142008-07-10 22:41:20 +00002159
2160 Return:
2161 Account instance
2162
2163 """
Benny Prijono55040452008-07-21 18:20:57 +00002164 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002165 err, acc_id = _pjsua.acc_add(acc_config._cvt_to_pjsua(), set_default)
2166 self._err_check("create_account()", self, err)
Benny Prijono55040452008-07-21 18:20:57 +00002167 return Account(self, acc_id, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00002168
Benny Prijono55040452008-07-21 18:20:57 +00002169 def create_account_for_transport(self, transport, set_default=True,
2170 cb=None):
Benny Prijono9c461142008-07-10 22:41:20 +00002171 """Create a new local pjsua transport for the specified transport.
2172
2173 Keyword arguments:
2174 transport -- the Transport instance.
2175 set_default -- boolean to specify whether to use this as the
2176 default account.
Benny Prijono55040452008-07-21 18:20:57 +00002177 cb -- AccountCallback instance.
Benny Prijono9c461142008-07-10 22:41:20 +00002178
2179 Return:
2180 Account instance
2181
2182 """
Benny Prijono55040452008-07-21 18:20:57 +00002183 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002184 err, acc_id = _pjsua.acc_add_local(transport._id, set_default)
2185 self._err_check("create_account_for_transport()", self, err)
Benny Prijono55040452008-07-21 18:20:57 +00002186 return Account(self, acc_id, cb)
Benny Prijono9c461142008-07-10 22:41:20 +00002187
2188 def hangup_all(self):
2189 """Hangup all calls.
2190
2191 """
Benny Prijono55040452008-07-21 18:20:57 +00002192 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002193 _pjsua.call_hangup_all()
2194
2195 # Sound device API
2196
2197 def enum_snd_dev(self):
2198 """Enumerate sound devices in the system.
2199
2200 Return:
Benny Prijono288d4bd2008-07-19 15:40:21 +00002201 list of SoundDeviceInfo. The index of the element specifies
Benny Prijono9c461142008-07-10 22:41:20 +00002202 the device ID for the device.
2203 """
Benny Prijono55040452008-07-21 18:20:57 +00002204 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002205 sdi_list = _pjsua.enum_snd_devs()
Benny Prijono9c461142008-07-10 22:41:20 +00002206 info = []
Benny Prijono288d4bd2008-07-19 15:40:21 +00002207 for sdi in sdi_list:
Benny Prijono9c461142008-07-10 22:41:20 +00002208 info.append(SoundDeviceInfo(sdi))
2209 return info
2210
2211 def get_snd_dev(self):
2212 """Get the device IDs of current sound devices used by pjsua.
2213
2214 Return:
2215 (capture_dev_id, playback_dev_id) tuple
2216 """
Benny Prijono55040452008-07-21 18:20:57 +00002217 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002218 return _pjsua.get_snd_dev()
2219
2220 def set_snd_dev(self, capture_dev, playback_dev):
2221 """Change the current sound devices.
2222
2223 Keyword arguments:
2224 capture_dev -- the device ID of capture device to be used
2225 playback_dev -- the device ID of playback device to be used.
2226
2227 """
Benny Prijono55040452008-07-21 18:20:57 +00002228 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002229 err = _pjsua.set_snd_dev(capture_dev, playback_dev)
2230 self._err_check("set_current_sound_devices()", self, err)
2231
2232 def set_null_snd_dev(self):
2233 """Disable the sound devices. This is useful if the system
2234 does not have sound device installed.
2235
2236 """
Benny Prijono55040452008-07-21 18:20:57 +00002237 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002238 err = _pjsua.set_null_snd_dev()
2239 self._err_check("set_null_snd_dev()", self, err)
2240
2241
2242 # Conference bridge
2243
2244 def conf_get_max_ports(self):
2245 """Get the conference bridge capacity.
2246
2247 Return:
2248 conference bridge capacity.
2249
2250 """
Benny Prijono55040452008-07-21 18:20:57 +00002251 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002252 return _pjsua.conf_get_max_ports()
2253
2254 def conf_connect(self, src_slot, dst_slot):
2255 """Establish unidirectional media flow from souce to sink.
2256
2257 One source may transmit to multiple destinations/sink. And if
2258 multiple sources are transmitting to the same sink, the media
2259 will be mixed together. Source and sink may refer to the same ID,
2260 effectively looping the media.
2261
2262 If bidirectional media flow is desired, application needs to call
2263 this function twice, with the second one having the arguments
2264 reversed.
2265
2266 Keyword arguments:
2267 src_slot -- integer to identify the conference slot number of
2268 the source/transmitter.
2269 dst_slot -- integer to identify the conference slot number of
2270 the destination/receiver.
2271
2272 """
Benny Prijono55040452008-07-21 18:20:57 +00002273 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002274 err = _pjsua.conf_connect(src_slot, dst_slot)
2275 self._err_check("conf_connect()", self, err)
2276
2277 def conf_disconnect(self, src_slot, dst_slot):
2278 """Disconnect media flow from the source to destination port.
2279
2280 Keyword arguments:
2281 src_slot -- integer to identify the conference slot number of
2282 the source/transmitter.
2283 dst_slot -- integer to identify the conference slot number of
2284 the destination/receiver.
2285
2286 """
Benny Prijono55040452008-07-21 18:20:57 +00002287 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002288 err = _pjsua.conf_disconnect(src_slot, dst_slot)
2289 self._err_check("conf_disconnect()", self, err)
2290
Benny Prijono288d4bd2008-07-19 15:40:21 +00002291 def conf_set_tx_level(self, slot, level):
2292 """Adjust the signal level to be transmitted from the bridge to
2293 the specified port by making it louder or quieter.
2294
2295 Keyword arguments:
2296 slot -- integer to identify the conference slot number.
2297 level -- Signal level adjustment. Value 1.0 means no level
2298 adjustment, while value 0 means to mute the port.
2299 """
Benny Prijono55040452008-07-21 18:20:57 +00002300 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002301 err = _pjsua.conf_set_tx_level(slot, level)
2302 self._err_check("conf_set_tx_level()", self, err)
2303
2304 def conf_set_rx_level(self, slot, level):
2305 """Adjust the signal level to be received from the specified port
2306 (to the bridge) by making it louder or quieter.
2307
2308 Keyword arguments:
2309 slot -- integer to identify the conference slot number.
2310 level -- Signal level adjustment. Value 1.0 means no level
2311 adjustment, while value 0 means to mute the port.
2312 """
Benny Prijono55040452008-07-21 18:20:57 +00002313 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002314 err = _pjsua.conf_set_rx_level(slot, level)
2315 self._err_check("conf_set_rx_level()", self, err)
2316
2317 def conf_get_signal_level(self, slot):
2318 """Get last signal level transmitted to or received from the
2319 specified port. The signal levels are float values from 0.0 to 1.0,
2320 with 0.0 indicates no signal, and 1.0 indicates the loudest signal
2321 level.
2322
2323 Keyword arguments:
2324 slot -- integer to identify the conference slot number.
2325
2326 Return value:
2327 (tx_level, rx_level) tuple.
2328 """
Benny Prijono55040452008-07-21 18:20:57 +00002329 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002330 err, tx_level, rx_level = _pjsua.conf_get_signal_level(slot)
2331 self._err_check("conf_get_signal_level()", self, err)
2332 return (tx_level, rx_level)
2333
2334
2335
Benny Prijono9c461142008-07-10 22:41:20 +00002336 # Codecs API
2337
2338 def enum_codecs(self):
2339 """Return list of codecs supported by pjsua.
2340
2341 Return:
Benny Prijono288d4bd2008-07-19 15:40:21 +00002342 list of CodecInfo
Benny Prijono9c461142008-07-10 22:41:20 +00002343
2344 """
Benny Prijono55040452008-07-21 18:20:57 +00002345 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002346 ci_list = _pjsua.enum_codecs()
Benny Prijono9c461142008-07-10 22:41:20 +00002347 codec_info = []
Benny Prijono288d4bd2008-07-19 15:40:21 +00002348 for ci in ci_list:
Benny Prijono0b627042008-08-18 11:32:13 +00002349 cp = _pjsua.codec_get_param(ci.codec_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002350 if cp:
2351 codec_info.append(CodecInfo(ci, cp))
2352 return codec_info
2353
2354 def set_codec_priority(self, name, priority):
2355 """Change the codec priority.
2356
2357 Keyword arguments:
2358 name -- Codec name
2359 priority -- Codec priority, which range is 0-255.
2360
2361 """
Benny Prijono55040452008-07-21 18:20:57 +00002362 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002363 err = _pjsua.codec_set_priority(name, priority)
2364 self._err_check("set_codec_priority()", self, err)
2365
2366 def get_codec_parameter(self, name):
2367 """Get codec parameter for the specified codec.
2368
2369 Keyword arguments:
2370 name -- codec name.
2371
2372 """
Benny Prijono55040452008-07-21 18:20:57 +00002373 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002374 cp = _pjsua.codec_get_param(name)
2375 if not cp:
2376 self._err_check("get_codec_parameter()", self, -1,
2377 "Invalid codec name")
2378 return CodecParameter(cp)
2379
2380 def set_codec_parameter(self, name, param):
2381 """Modify codec parameter for the specified codec.
2382
2383 Keyword arguments:
2384 name -- codec name
2385 param -- codec parameter.
2386
2387 """
Benny Prijono55040452008-07-21 18:20:57 +00002388 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002389 err = _pjsua.codec_set_param(name, param._cvt_to_pjsua())
2390 self._err_check("set_codec_parameter()", self, err)
2391
2392 # WAV playback and recording
2393
2394 def create_player(self, filename, loop=False):
2395 """Create WAV file player.
2396
2397 Keyword arguments
2398 filename -- WAV file name
Benny Prijono288d4bd2008-07-19 15:40:21 +00002399 loop -- boolean to specify whether playback should
2400 automatically restart upon EOF
Benny Prijono9c461142008-07-10 22:41:20 +00002401 Return:
2402 WAV player ID
2403
2404 """
Benny Prijono55040452008-07-21 18:20:57 +00002405 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002406 opt = 0
2407 if not loop:
2408 opt = opt + 1
2409 err, player_id = _pjsua.player_create(filename, opt)
2410 self._err_check("create_player()", self, err)
2411 return player_id
2412
2413 def player_get_slot(self, player_id):
2414 """Get the conference port ID for the specified player.
2415
2416 Keyword arguments:
2417 player_id -- the WAV player ID
2418
2419 Return:
2420 Conference slot number for the player
2421
2422 """
Benny Prijono55040452008-07-21 18:20:57 +00002423 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002424 slot = _pjsua.player_get_conf_port(player_id)
Benny Prijono940bd3e2008-07-11 09:14:40 +00002425 if slot < 0:
2426 self._err_check("player_get_slot()", self, -1,
2427 "Invalid player id")
Benny Prijono9c461142008-07-10 22:41:20 +00002428 return slot
2429
2430 def player_set_pos(self, player_id, pos):
2431 """Set WAV playback position.
2432
2433 Keyword arguments:
2434 player_id -- WAV player ID
2435 pos -- playback position, in samples
2436
2437 """
Benny Prijono55040452008-07-21 18:20:57 +00002438 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002439 err = _pjsua.player_set_pos(player_id, pos)
2440 self._err_check("player_set_pos()", self, err)
2441
2442 def player_destroy(self, player_id):
2443 """Destroy the WAV player.
2444
2445 Keyword arguments:
2446 player_id -- the WAV player ID.
2447
2448 """
Benny Prijono55040452008-07-21 18:20:57 +00002449 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002450 err = _pjsua.player_destroy(player_id)
2451 self._err_check("player_destroy()", self, err)
2452
Benny Prijono288d4bd2008-07-19 15:40:21 +00002453 def create_playlist(self, filelist, label="playlist", loop=True):
2454 """Create WAV playlist.
2455
2456 Keyword arguments:
2457 filelist -- List of WAV file names.
2458 label -- Optional name to be assigned to the playlist
2459 object (useful for logging)
2460 loop -- boolean to specify whether playback should
2461 automatically restart upon EOF
2462
2463 Return:
2464 playlist_id
2465 """
Benny Prijono55040452008-07-21 18:20:57 +00002466 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002467 opt = 0
2468 if not loop:
2469 opt = opt + 1
2470 err, playlist_id = _pjsua.playlist_create(label, filelist, opt)
2471 self._err_check("create_playlist()", self, err)
2472 return playlist_id
2473
2474 def playlist_get_slot(self, playlist_id):
2475 """Get the conference port ID for the specified playlist.
2476
2477 Keyword arguments:
2478 playlist_id -- the WAV playlist ID
2479
2480 Return:
2481 Conference slot number for the playlist
2482
2483 """
Benny Prijono55040452008-07-21 18:20:57 +00002484 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002485 slot = _pjsua.player_get_conf_port(playlist_id)
2486 if slot < 0:
2487 self._err_check("playlist_get_slot()", self, -1,
2488 "Invalid playlist id")
2489 return slot
2490
2491 def playlist_destroy(self, playlist_id):
2492 """Destroy the WAV playlist.
2493
2494 Keyword arguments:
2495 playlist_id -- the WAV playlist ID.
2496
2497 """
Benny Prijono55040452008-07-21 18:20:57 +00002498 lck = self.auto_lock()
Benny Prijono288d4bd2008-07-19 15:40:21 +00002499 err = _pjsua.player_destroy(playlist_id)
2500 self._err_check("playlist_destroy()", self, err)
2501
Benny Prijono9c461142008-07-10 22:41:20 +00002502 def create_recorder(self, filename):
2503 """Create WAV file recorder.
2504
2505 Keyword arguments
2506 filename -- WAV file name
2507
2508 Return:
2509 WAV recorder ID
2510
2511 """
Benny Prijono55040452008-07-21 18:20:57 +00002512 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002513 err, rec_id = _pjsua.recorder_create(filename, 0, None, -1, 0)
2514 self._err_check("create_recorder()", self, err)
2515 return rec_id
2516
2517 def recorder_get_slot(self, rec_id):
2518 """Get the conference port ID for the specified recorder.
2519
2520 Keyword arguments:
2521 rec_id -- the WAV recorder ID
2522
2523 Return:
2524 Conference slot number for the recorder
2525
2526 """
Benny Prijono55040452008-07-21 18:20:57 +00002527 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002528 slot = _pjsua.recorder_get_conf_port(rec_id)
Benny Prijono940bd3e2008-07-11 09:14:40 +00002529 if slot < 1:
2530 self._err_check("recorder_get_slot()", self, -1,
2531 "Invalid recorder id")
Benny Prijono9c461142008-07-10 22:41:20 +00002532 return slot
2533
2534 def recorder_destroy(self, rec_id):
2535 """Destroy the WAV recorder.
2536
2537 Keyword arguments:
2538 rec_id -- the WAV recorder ID.
2539
2540 """
Benny Prijono55040452008-07-21 18:20:57 +00002541 lck = self.auto_lock()
Benny Prijono9c461142008-07-10 22:41:20 +00002542 err = _pjsua.recorder_destroy(rec_id)
2543 self._err_check("recorder_destroy()", self, err)
2544
2545
2546 # Internal functions
2547
2548 @staticmethod
2549 def strerror(err):
2550 return _pjsua.strerror(err)
2551
2552 def _err_check(self, op_name, obj, err_code, err_msg=""):
2553 if err_code != 0:
2554 raise Error(op_name, obj, err_code, err_msg)
2555
2556 @staticmethod
2557 def _create_msg_data(hdr_list):
2558 if not hdr_list:
2559 return None
2560 msg_data = _pjsua.Msg_Data()
2561 msg_data.hdr_list = hdr_list
2562 return msg_data
2563
Benny Prijono55040452008-07-21 18:20:57 +00002564 def auto_lock(self):
2565 return _LibMutex(self._lock)
2566
Benny Prijono9c461142008-07-10 22:41:20 +00002567 # Internal dictionary manipulation for calls, accounts, and buddies
2568
Benny Prijono9c461142008-07-10 22:41:20 +00002569 def _lookup_call(self, call_id):
Benny Prijono55040452008-07-21 18:20:57 +00002570 return _pjsua.call_get_user_data(call_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002571
2572 def _lookup_account(self, acc_id):
Benny Prijono55040452008-07-21 18:20:57 +00002573 return _pjsua.acc_get_user_data(acc_id)
Benny Prijono9c461142008-07-10 22:41:20 +00002574
2575 def _lookup_buddy(self, buddy_id, uri=None):
Benny Prijono55040452008-07-21 18:20:57 +00002576 if buddy_id != -1:
2577 buddy = _pjsua.buddy_get_user_data(buddy_id)
2578 elif uri:
2579 buddy_id = _pjsua.buddy_find(uri)
2580 if buddy_id != -1:
2581 buddy = _pjsua.buddy_get_user_data(buddy_id)
2582 else:
2583 buddy = None
2584 else:
2585 buddy = None
2586
Benny Prijono9c461142008-07-10 22:41:20 +00002587 return buddy
2588
Benny Prijono9c461142008-07-10 22:41:20 +00002589 # Account allbacks
2590
2591 def _cb_on_reg_state(self, acc_id):
2592 acc = self._lookup_account(acc_id)
2593 if acc:
2594 acc._cb.on_reg_state()
2595
Benny Prijono55040452008-07-21 18:20:57 +00002596 def _cb_on_incoming_subscribe(self, acc_id, buddy_id, from_uri,
2597 contact_uri, pres_obj):
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002598 acc = self._lookup_account(acc_id)
2599 if acc:
2600 buddy = self._lookup_buddy(buddy_id)
Benny Prijono55040452008-07-21 18:20:57 +00002601 return acc._cb.on_incoming_subscribe(buddy, from_uri, contact_uri,
2602 pres_obj)
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002603 else:
2604 return (404, None)
2605
Benny Prijono9c461142008-07-10 22:41:20 +00002606 def _cb_on_incoming_call(self, acc_id, call_id, rdata):
2607 acc = self._lookup_account(acc_id)
2608 if acc:
2609 acc._cb.on_incoming_call( Call(self, call_id) )
2610 else:
2611 _pjsua.call_hangup(call_id, 603, None, None)
2612
2613 # Call callbacks
2614
2615 def _cb_on_call_state(self, call_id):
2616 call = self._lookup_call(call_id)
2617 if call:
Benny Prijono55040452008-07-21 18:20:57 +00002618 if call._id == -1:
2619 call.attach_to_id(call_id)
2620 done = (call.info().state == CallState.DISCONNECTED)
Benny Prijono9c461142008-07-10 22:41:20 +00002621 call._cb.on_state()
Benny Prijono55040452008-07-21 18:20:57 +00002622 if done:
2623 _pjsua.call_set_user_data(call_id, 0)
2624 else:
2625 pass
Benny Prijono9c461142008-07-10 22:41:20 +00002626
2627 def _cb_on_call_media_state(self, call_id):
2628 call = self._lookup_call(call_id)
2629 if call:
2630 call._cb.on_media_state()
2631
2632 def _cb_on_dtmf_digit(self, call_id, digits):
2633 call = self._lookup_call(call_id)
2634 if call:
2635 call._cb.on_dtmf_digit(digits)
2636
2637 def _cb_on_call_transfer_request(self, call_id, dst, code):
2638 call = self._lookup_call(call_id)
2639 if call:
2640 return call._cb.on_transfer_request(dst, code)
2641 else:
2642 return 603
2643
2644 def _cb_on_call_transfer_status(self, call_id, code, text, final, cont):
2645 call = self._lookup_call(call_id)
2646 if call:
2647 return call._cb.on_transfer_status(code, text, final, cont)
2648 else:
2649 return cont
2650
2651 def _cb_on_call_replace_request(self, call_id, rdata, code, reason):
2652 call = self._lookup_call(call_id)
2653 if call:
2654 return call._cb.on_replace_request(code, reason)
2655 else:
2656 return code, reason
2657
2658 def _cb_on_call_replaced(self, old_call_id, new_call_id):
2659 old_call = self._lookup_call(old_call_id)
2660 new_call = self._lookup_call(new_call_id)
2661 if old_call and new_call:
2662 old_call._cb.on_replaced(new_call)
2663
2664 def _cb_on_pager(self, call_id, from_uri, to_uri, contact, mime_type,
2665 body, acc_id):
2666 call = None
2667 if call_id == -1:
2668 call = self._lookup_call(call_id)
2669 if call:
2670 call._cb.on_pager(mime_type, body)
2671 else:
2672 acc = self._lookup_account(acc_id)
2673 buddy = self._lookup_buddy(-1, from_uri)
2674 if buddy:
2675 buddy._cb.on_pager(mime_type, body)
2676 else:
2677 acc._cb.on_pager(from_uri, contact, mime_type, body)
2678
2679 def _cb_on_pager_status(self, call_id, to_uri, body, user_data,
2680 code, reason, acc_id):
2681 call = None
2682 if call_id == -1:
2683 call = self._lookup_call(call_id)
2684 if call:
2685 call._cb.on_pager_status(body, user_data, code, reason)
2686 else:
2687 acc = self._lookup_account(acc_id)
2688 buddy = self._lookup_buddy(-1, to_uri)
2689 if buddy:
2690 buddy._cb.on_pager_status(body, user_data, code, reason)
2691 else:
2692 acc._cb.on_pager_status(to_uri, body, user_data, code, reason)
2693
2694 def _cb_on_typing(self, call_id, from_uri, to_uri, contact, is_typing,
2695 acc_id):
2696 call = None
2697 if call_id == -1:
2698 call = self._lookup_call(call_id)
2699 if call:
2700 call._cb.on_typing(is_typing)
2701 else:
2702 acc = self._lookup_account(acc_id)
2703 buddy = self._lookup_buddy(-1, from_uri)
2704 if buddy:
2705 buddy._cb.on_typing(is_typing)
2706 else:
2707 acc._cb.on_typing(from_uri, contact, is_typing)
2708
2709 def _cb_on_buddy_state(self, buddy_id):
2710 buddy = self._lookup_buddy(buddy_id)
2711 if buddy:
2712 buddy._cb.on_state()
2713
2714
2715
2716
2717#
2718# Internal
2719#
2720
2721def _cb_on_call_state(call_id, e):
2722 _lib._cb_on_call_state(call_id)
2723
2724def _cb_on_incoming_call(acc_id, call_id, rdata):
2725 _lib._cb_on_incoming_call(acc_id, call_id, rdata)
2726
2727def _cb_on_call_media_state(call_id):
2728 _lib._cb_on_call_media_state(call_id)
2729
2730def _cb_on_dtmf_digit(call_id, digits):
2731 _lib._cb_on_dtmf_digit(call_id, digits)
2732
2733def _cb_on_call_transfer_request(call_id, dst, code):
2734 return _lib._cb_on_call_transfer_request(call_id, dst, code)
2735
2736def _cb_on_call_transfer_status(call_id, code, reason, final, cont):
2737 return _lib._cb_on_call_transfer_status(call_id, code, reason,
2738 final, cont)
2739def _cb_on_call_replace_request(call_id, rdata, code, reason):
2740 return _lib._cb_on_call_replace_request(call_id, rdata, code, reason)
2741
2742def _cb_on_call_replaced(old_call_id, new_call_id):
2743 _lib._cb_on_call_replaced(old_call_id, new_call_id)
2744
2745def _cb_on_reg_state(acc_id):
2746 _lib._cb_on_reg_state(acc_id)
2747
Benny Prijono55040452008-07-21 18:20:57 +00002748def _cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, contact_uri, pres):
2749 return _lib._cb_on_incoming_subscribe(acc_id, buddy_id, from_uri,
2750 contact_uri, pres)
Benny Prijonoe6787ec2008-07-18 23:00:56 +00002751
Benny Prijono9c461142008-07-10 22:41:20 +00002752def _cb_on_buddy_state(buddy_id):
2753 _lib._cb_on_buddy_state(buddy_id)
2754
2755def _cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id):
2756 _lib._cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id)
2757
2758def _cb_on_pager_status(call_id, to, body, user_data, status, reason, acc_id):
2759 _lib._cb_on_pager_status(call_id, to, body, user_data,
2760 status, reason, acc_id)
2761
2762def _cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id):
2763 _lib._cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id)
2764
2765
2766# Worker thread
2767def _worker_thread_main(arg):
2768 global _lib
Benny Prijono6ecef072008-07-21 22:46:35 +00002769 _Trace(('worker thread started..',))
Benny Prijono9c461142008-07-10 22:41:20 +00002770 thread_desc = 0;
2771 err = _pjsua.thread_register("python worker", thread_desc)
2772 _lib._err_check("thread_register()", _lib, err)
Benny Prijono55040452008-07-21 18:20:57 +00002773 while _lib and _lib._quit == 0:
Benny Prijono6ecef072008-07-21 22:46:35 +00002774 _lib.handle_events(1)
2775 time.sleep(0.050)
Benny Prijono55040452008-07-21 18:20:57 +00002776 if _lib:
2777 _lib._quit = 2
Benny Prijono6ecef072008-07-21 22:46:35 +00002778 _Trace(('worker thread exited..',))
Benny Prijono9c461142008-07-10 22:41:20 +00002779
Benny Prijono55040452008-07-21 18:20:57 +00002780def _Trace(args):
Benny Prijonofd47c2c2008-07-24 09:00:28 +00002781 global enable_trace
2782 if enable_trace:
Benny Prijono55040452008-07-21 18:20:57 +00002783 print "** ",
2784 for arg in args:
2785 print arg,
2786 print " **"
Benny Prijono6ecef072008-07-21 22:46:35 +00002787