1
# $Id: pjsua.py 2976 2009-10-29 08:16:46Z bennylp $
3
# Object oriented PJSUA wrapper.
5
# Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
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.
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
22
"""Multimedia communication client library based on SIP protocol.
24
This implements a fully featured multimedia communication client
25
library based on PJSIP stack (http://www.pjsip.org)
30
- Session Initiation Protocol (SIP) features:
31
- Basic registration and call
33
- Call hold, attended and unattended call transfer
36
- Multiple SIP accounts
40
- Narrowband and wideband
41
- Codecs: PCMA, PCMU, GSM, iLBC, Speex, G.722, L16
44
- WAV playback, recording, and playlist
45
- NAT traversal features
54
See http://www.pjsip.org/trac/wiki/Python_SIP_Tutorial for a more thorough
55
tutorial. The paragraphs below explain basic tasks on using this module.
66
"""Error exception class.
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.
80
def __init__(self, op_name, obj, err_code, err_msg=""):
81
self.op_name = op_name
83
self.err_code = err_code
84
self._err_msg = err_msg
87
"Retrieve the description of the error."
88
if self._err_msg != "":
90
self._err_msg = Lib.strerror(self.err_code)
94
return "Object: " + str(self.obj) + ", operation=" + self.op_name + \
95
", error=" + self.err_msg()
102
"""SIP transport type constants.
104
Member documentation:
105
UNSPECIFIED -- transport type is unknown or unspecified
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
119
UDP_IPV6 = UDP + IPV6
120
TCP_IPV6 = TCP + IPV6
123
"""Transport flags to indicate the characteristics of the transport.
125
Member documentation:
127
RELIABLE -- transport is reliable.
128
SECURE -- transport is secure.
129
DATAGRAM -- transport is datagram based.
137
"""Call role constants.
139
Member documentation:
141
CALLER -- role is caller
142
CALLEE -- role is callee
149
"""Call state constants.
151
Member documentation:
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.
171
"""Call media state constants.
173
Member documentation:
175
NULL -- media is not available.
176
ACTIVE -- media is active.
177
LOCAL_HOLD -- media is put on-hold by local party.
178
REMOTE_HOLD -- media is put on-hold by remote party.
179
ERROR -- media error (e.g. ICE negotiation failure).
189
"""Media direction constants.
191
Member documentation:
193
NULL -- media is not active
194
ENCODING -- media is active in transmit/encoding direction only.
195
DECODING -- media is active in receive/decoding direction only
196
ENCODING_DECODING -- media is active in both directions.
201
ENCODING_DECODING = 3
204
class PresenceActivity:
205
"""Presence activities constants.
207
Member documentation:
209
UNKNOWN -- the person activity is unknown
210
AWAY -- the person is currently away
211
BUSY -- the person is currently engaging in other activity
218
class SubscriptionState:
219
"""Presence subscription state constants.
232
"""These constants specifies the connection type to TURN server.
234
Member documentation:
235
UDP -- use UDP transport.
236
TCP -- use TCP transport.
237
TLS -- use TLS transport.
245
"""User agent configuration to be specified in Lib.init().
247
Member documentation:
249
max_calls -- maximum number of calls to be supported.
250
nameserver -- list of nameserver hostnames or IP addresses. Nameserver
251
must be configured if DNS SRV resolution is desired.
252
stun_domain -- if nameserver is configured, this can be used to query
253
the STUN server with DNS SRV.
254
stun_host -- the hostname or IP address of the STUN server. This will
255
also be used if DNS SRV resolution for stun_domain fails.
256
user_agent -- Optionally specify the user agent name.
262
user_agent = "pjsip python"
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
272
def _cvt_to_pjsua(self):
273
cfg = _pjsua.config_default()
274
cfg.max_calls = self.max_calls
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
284
"""Logging configuration to be specified in Lib.init().
286
Member documentation:
288
msg_logging -- specify if SIP messages should be logged. Set to
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:
297
def log_cb(level, str, len):
308
def __init__(self, level=-1, filename="", callback=None,
310
self._cvt_from_pjsua(_pjsua.logging_config_default())
314
self.filename = filename
316
self.callback = callback
317
if console_level != -1:
318
self.console_level = console_level
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
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
340
"""Media configuration to be specified in Lib.init().
342
Member documentation:
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
348
snd_auto_close_time -- specify the duration in seconds when the
349
sound device should be closed after inactivity
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
359
no_vad -- disable Voice Activity Detector (VAD) or Silence
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
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.
384
snd_auto_close_time = 5
386
audio_frame_ptime = 20
401
turn_conn_type = TURNConnType.UDP
405
default = _pjsua.media_config_default()
406
self._cvt_from_pjsua(default)
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)
433
self.turn_cred = None
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
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
465
class TransportConfig:
466
"""SIP transport configuration class.
468
Member configuration:
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".
482
def __init__(self, port=0,
483
bound_addr="", public_addr=""):
485
self.bound_addr = bound_addr
486
self.public_addr = public_addr
488
def _cvt_to_pjsua(self):
489
cfg = _pjsua.transport_config_default()
491
cfg.bound_addr = self.bound_addr
492
cfg.public_addr = self.public_addr
497
"""SIP transport info.
499
Member documentation:
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.
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)
527
self.ref_cnt = ti.usage_count
531
"SIP transport class."
536
def __init__(self, lib, id):
537
self._lib = weakref.proxy(lib)
539
self._obj_name = "{Transport " + self.info().description + "}"
540
_Trace((self, 'created'))
543
_Trace((self, 'destroyed'))
546
return self._obj_name
549
"""Get TransportInfo.
551
lck = self._lib.auto_lock()
552
ti = _pjsua.transport_get_info(self._id)
554
self._lib._err_check("info()", self, -1, "Invalid transport")
555
return TransportInfo(ti)
558
"""Enable this transport."""
559
lck = self._lib.auto_lock()
560
err = _pjsua.transport_set_enable(self._id, True)
561
self._lib._err_check("enable()", self, err)
564
"""Disable this transport."""
565
lck = self._lib.auto_lock()
566
err = _pjsua.transport_set_enable(self._id, 0)
567
self._lib._err_check("disable()", self, err)
569
def close(self, force=False):
570
"""Close and destroy this transport.
573
force -- force deletion of this transport (not recommended).
575
lck = self._lib.auto_lock()
576
err = _pjsua.transport_close(self._id, force)
577
self._lib._err_check("close()", self, err)
581
"""Helper class to parse the most important components of SIP URI.
583
Member documentation:
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
599
def __init__(self, uri=None):
603
def decode(self, uri):
607
uri -- the URI string.
610
self.scheme, self.user, self.host, self.port, self.transport = \
611
_pjsua.parse_simple_uri(uri)
614
"""Encode this object into SIP URI string.
620
output = self.scheme + ":"
621
if self.user and len(self.user):
622
output = output + self.user + "@"
623
output = output + self.host
625
output = output + ":" + output(self.port)
627
output = output + ";transport=" + self.transport
632
"""Authentication credential for SIP or TURN account.
634
Member documentation:
636
scheme -- authentication scheme (default is "Digest")
639
passwd_type -- password encoding (zero for plain-text)
640
passwd -- the password
648
def __init__(self, realm, username, passwd, scheme="Digest", passwd_type=0):
651
self.username = username
652
self.passwd_type = passwd_type
657
""" This describes account configuration to create an account.
659
Member documentation:
661
priority -- account priority for matching incoming
663
id -- SIP URI of this account. This setting is
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
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
676
pidf_tuple_id -- optionally specify the tuple ID in outgoing
678
proxy -- list of proxy URI.
679
auth_cred -- list of AuthCred containing credentials to
680
authenticate against the registrars and
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
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
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
696
ka_interval -- specify the interval to send NAT keep-alive
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.
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").
713
require_100rel = False
714
publish_enabled = False
718
auth_initial_send = False
719
auth_initial_algorithm = ""
721
allow_contact_rewrite = True
725
srtp_secure_signaling = 1
727
def __init__(self, domain="", username="", password="",
728
display="", registrar="", proxy=""):
730
Construct account config. If domain argument is specified,
731
a typical configuration will be built.
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.
746
default = _pjsua.acc_config_default()
747
self._cvt_from_pjsua(default)
749
self.build_config(domain, username, password,
750
display, registrar, proxy)
752
def build_config(self, domain, username, password, display="",
753
registrar="", proxy=""):
755
Construct account config. If domain argument is specified,
756
a typical configuration will be built.
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.
772
display = display + " "
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
781
proxy = "sip:" + domain + ";lr"
782
if proxy.find(";lr") == -1:
783
proxy = proxy + ";lr"
784
self.proxy.append(proxy)
786
self.auth_cred.append(AuthCred("*", username, password))
788
def _cvt_from_pjsua(self, cfg):
789
self.priority = cfg.priority
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,
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
811
def _cvt_to_pjsua(self):
812
cfg = _pjsua.acc_config_default()
813
cfg.priority = self.priority
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()
825
c.scheme = cred.scheme
826
c.username = cred.username
827
c.data_type = cred.passwd_type
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
841
# Account information
843
"""This describes Account info. Application retrives account info
846
Member documentation:
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,
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
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.
869
online_status = False
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
883
class AccountCallback:
884
"""Class to receive notifications on account's events.
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
890
Member documentation:
892
account -- the Account object.
897
def __init__(self, account=None):
898
self._set_account(account)
903
def _set_account(self, account):
905
self.account = weakref.proxy(account)
909
def on_reg_state(self):
910
"""Notification that the registration status has changed.
914
def on_incoming_call(self, call):
915
"""Notification about incoming call.
917
Unless this callback is implemented, the default behavior is to
918
reject the call with default status code.
921
call -- the new incoming call
925
def on_incoming_subscribe(self, buddy, from_uri, contact_uri, pres_obj):
926
"""Notification when incoming SUBSCRIBE request is received.
928
Application may use this callback to authorize the incoming
929
subscribe request (e.g. ask user permission if the request
933
buddy -- The buddy object, if buddy is found. Otherwise
935
from_uri -- The URI string of the sender.
936
pres_obj -- Opaque presence subscription object, which is
937
needed by Account.pres_notify()
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.
952
def on_pager(self, from_uri, contact, mime_type, body):
954
Notification that incoming instant message is received on
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
966
def on_pager_status(self, to_uri, body, im_id, code, reason):
968
Notification about the delivery status of previously sent
972
to_uri -- the destination URI of the message
973
body -- the message body
975
code -- SIP status code
976
reason -- SIP reason phrase
981
def on_typing(self, from_uri, contact, is_typing):
983
Notification that remote is typing or stop typing.
986
buddy -- Buddy object for the sender, if found. Otherwise
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.
996
def on_mwi_info(self, body):
998
Notification about change in Message Summary / Message Waiting
999
Indication (RFC 3842) status. MWI subscription must be enabled
1000
in the account config to receive this notification.
1003
body -- String containing message body as received in the
1012
"""This describes SIP account class.
1014
PJSUA accounts provide identity (or identities) of the user who is
1015
currently using the application. In SIP terms, the identity is used
1016
as the From header in outgoing requests.
1018
Account may or may not have client registration associated with it.
1019
An account is also associated with route set and some authentication
1020
credentials, which are used when sending SIP request messages using
1021
the account. An account also has presence's online status, which
1022
will be reported to remote peer when they subscribe to the account's
1023
presence, or which is published to a presence server if presence
1024
publication is enabled for the account.
1026
Account is created with Lib.create_account(). At least one account
1027
MUST be created. If no user association is required, application can
1028
create a userless account by calling Lib.create_account_for_transport().
1029
A userless account identifies local endpoint instead of a particular
1030
user, and it correspond with a particular transport instance.
1032
Also one account must be set as the default account, which is used as
1033
the account to use when PJSUA fails to match a request with any other
1039
_cb = AccountCallback(None)
1042
def __init__(self, lib, id, cb=None):
1043
"""Construct this class. This is normally called by Lib class and
1047
lib -- the Lib instance.
1048
id -- the pjsua account ID.
1049
cb -- AccountCallback instance to receive events from this Account.
1050
If callback is not specified here, it must be set later
1051
using set_callback().
1054
self._lib = weakref.ref(lib)
1055
self._obj_name = "{Account " + self.info().uri + "}"
1056
self.set_callback(cb)
1057
_pjsua.acc_set_user_data(self._id, self)
1058
_Trace((self, 'created'))
1062
_pjsua.acc_set_user_data(self._id, 0)
1063
_Trace((self, 'destroyed'))
1066
return self._obj_name
1069
"""Retrieve AccountInfo for this account.
1071
lck = self._lib().auto_lock()
1072
ai = _pjsua.acc_get_info(self._id)
1074
self._lib()._err_check("info()", self, -1, "Invalid account")
1075
return AccountInfo(ai)
1079
Check if this account is still valid.
1082
lck = self._lib().auto_lock()
1083
return _pjsua.acc_is_valid(self._id)
1085
def set_callback(self, cb):
1086
"""Register callback to receive notifications from this object.
1089
cb -- AccountCallback instance.
1095
self._cb = AccountCallback(self)
1096
self._cb._set_account(self)
1098
def set_default(self):
1099
""" Set this account as default account to send outgoing requests
1100
and as the account to receive incoming requests when more exact
1101
matching criteria fails.
1103
lck = self._lib().auto_lock()
1104
err = _pjsua.acc_set_default(self._id)
1105
self._lib()._err_check("set_default()", self, err)
1107
def is_default(self):
1108
""" Check if this account is the default account.
1111
lck = self._lib().auto_lock()
1112
def_id = _pjsua.acc_get_default()
1113
return self.is_valid() and def_id==self._id
1116
""" Delete this account.
1119
lck = self._lib().auto_lock()
1120
err = _pjsua.acc_set_user_data(self._id, 0)
1121
self._lib()._err_check("delete()", self, err)
1122
err = _pjsua.acc_del(self._id)
1123
self._lib()._err_check("delete()", self, err)
1126
def set_basic_status(self, is_online):
1127
""" Set basic presence status of this account.
1130
is_online -- boolean to indicate basic presence availability.
1133
lck = self._lib().auto_lock()
1134
err = _pjsua.acc_set_online_status(self._id, is_online)
1135
self._lib()._err_check("set_basic_status()", self, err)
1137
def set_presence_status(self, is_online,
1138
activity=PresenceActivity.UNKNOWN,
1139
pres_text="", rpid_id=""):
1140
""" Set presence status of this account.
1143
is_online -- boolean to indicate basic presence availability
1144
activity -- value from PresenceActivity
1145
pres_text -- optional string to convey additional information about
1146
the activity (such as "On the phone")
1147
rpid_id -- optional string to be placed as RPID ID.
1150
lck = self._lib().auto_lock()
1151
err = _pjsua.acc_set_online_status2(self._id, is_online, activity,
1153
self._lib()._err_check("set_presence_status()", self, err)
1155
def set_registration(self, renew):
1156
"""Manually renew registration or unregister from the server.
1159
renew -- boolean to indicate whether registration is renewed.
1160
Setting this value for False will trigger unregistration.
1163
lck = self._lib().auto_lock()
1164
err = _pjsua.acc_set_registration(self._id, renew)
1165
self._lib()._err_check("set_registration()", self, err)
1167
def set_transport(self, transport):
1168
"""Set this account to only use the specified transport to send
1172
transport -- Transport object.
1175
lck = self._lib().auto_lock()
1176
err = _pjsua.acc_set_transport(self._id, transport._id)
1177
self._lib()._err_check("set_transport()", self, err)
1179
def make_call(self, dst_uri, cb=None, hdr_list=None):
1180
"""Make outgoing call to the specified URI.
1183
dst_uri -- Destination SIP URI.
1184
cb -- CallCallback instance to be installed to the newly
1185
created Call object. If this CallCallback is not
1186
specified (i.e. None is given), it must be installed
1187
later using call.set_callback().
1188
hdr_list -- Optional list of headers to be sent with outgoing
1194
lck = self._lib().auto_lock()
1195
call = Call(self._lib(), -1, cb)
1196
err, cid = _pjsua.call_make_call(self._id, dst_uri, 0,
1197
call, Lib._create_msg_data(hdr_list))
1198
self._lib()._err_check("make_call()", self, err)
1199
call.attach_to_id(cid)
1202
def add_buddy(self, uri, cb=None):
1206
uri -- SIP URI of the buddy
1207
cb -- BuddyCallback instance to be installed to the newly
1208
created Buddy object. If this callback is not specified
1209
(i.e. None is given), it must be installed later using
1210
buddy.set_callback().
1215
lck = self._lib().auto_lock()
1216
buddy_cfg = _pjsua.buddy_config_default()
1218
buddy_cfg.subscribe = False
1219
err, buddy_id = _pjsua.buddy_add(buddy_cfg)
1220
self._lib()._err_check("add_buddy()", self, err)
1221
buddy = Buddy(self._lib(), buddy_id, self, cb)
1224
def pres_notify(self, pres_obj, state, reason="", hdr_list=None):
1225
"""Send NOTIFY to inform account presence status or to terminate
1226
server side presence subscription.
1229
pres_obj -- The subscription object from on_incoming_subscribe()
1231
state -- Subscription state, from SubscriptionState
1232
reason -- Optional reason phrase.
1233
hdr_list -- Optional header list.
1235
lck = self._lib().auto_lock()
1236
_pjsua.acc_pres_notify(self._id, pres_obj, state, reason,
1237
Lib._create_msg_data(hdr_list))
1239
def send_pager(self, uri, text, im_id=0, content_type="text/plain", \
1241
"""Send instant message to arbitrary URI.
1244
text -- Instant message to be sent
1245
uri -- URI to send the Instant Message to.
1246
im_id -- Optional instant message ID to identify this
1247
instant message when delivery status callback
1249
content_type -- MIME type identifying the instant message
1250
hdr_list -- Optional list of headers to be sent with the
1254
lck = self._lib().auto_lock()
1255
err = _pjsua.im_send(self._id, uri, \
1256
content_type, text, \
1257
Lib._create_msg_data(hdr_list), \
1259
self._lib()._err_check("send_pager()", self, err)
1262
"""Class to receive event notification from Call objects.
1264
Use Call.set_callback() method to install instance of this callback
1265
class to receive event notifications from the call object.
1267
Member documentation:
1269
call -- the Call object.
1274
def __init__(self, call=None):
1275
self._set_call(call)
1280
def _set_call(self, call):
1282
self.call = weakref.proxy(call)
1287
"""Notification that the call's state has changed.
1292
def on_media_state(self):
1293
"""Notification that the call's media state has changed.
1298
def on_dtmf_digit(self, digits):
1299
"""Notification on incoming DTMF digits.
1302
digits -- string containing the received digits.
1307
def on_transfer_request(self, dst, code):
1308
"""Notification that call is being transfered by remote party.
1310
Application can decide to accept/reject transfer request by returning
1311
code greater than or equal to 500. The default behavior is to accept
1312
the transfer by returning 202.
1315
dst -- string containing the destination URI
1316
code -- the suggested status code to return to accept the request.
1319
the callback should return 202 to accept the request, or 300-699 to
1325
def on_transfer_status(self, code, reason, final, cont):
1327
Notification about the status of previous call transfer request.
1330
code -- SIP status code to indicate completion status.
1331
text -- SIP status reason phrase.
1332
final -- if True then this is a final status and no further
1333
notifications will be sent for this call transfer
1335
cont -- suggested return value.
1338
If the callback returns false then no further notification will
1339
be sent for the transfer request for this call.
1344
def on_replace_request(self, code, reason):
1345
"""Notification when incoming INVITE with Replaces header is received.
1347
Application may reject the request by returning value greather than
1348
or equal to 500. The default behavior is to accept the request.
1351
code -- default status code to return
1352
reason -- default reason phrase to return
1355
The callback should return (code, reason) tuple.
1360
def on_replaced(self, new_call):
1362
Notification that this call will be replaced with new_call.
1363
After this callback is called, this call will be disconnected.
1366
new_call -- the new call that will replace this call.
1370
def on_pager(self, mime_type, body):
1372
Notification that incoming instant message is received on
1376
mime_type -- MIME type of the instant message body.
1377
body -- the instant message body.
1382
def on_pager_status(self, body, im_id, code, reason):
1384
Notification about the delivery status of previously sent
1388
body -- message body
1390
code -- SIP status code
1391
reason -- SIP reason phrase
1396
def on_typing(self, is_typing):
1398
Notification that remote is typing or stop typing.
1401
is_typing -- boolean to indicate whether remote is currently
1402
typing an instant message.
1409
"""This structure contains various information about Call.
1411
Application may retrieve this information with Call.info().
1413
Member documentation:
1416
account -- Account object.
1417
uri -- SIP URI of local account.
1418
contact -- local Contact URI.
1419
remote_uri -- remote SIP URI.
1420
remote_contact -- remote Contact URI
1421
sip_call_id -- call's Call-ID identification
1423
state_text -- state text.
1424
last_code -- last SIP status code
1425
last_reason -- text phrase for last_code
1426
media_state -- MediaState
1427
media_dir -- MediaDir
1428
conf_slot -- conference slot number for this call.
1429
call_time -- call's connected duration in seconds.
1430
total_time -- total call duration in seconds.
1432
role = CallRole.CALLER
1439
state = CallState.NULL
1443
media_state = MediaState.NULL
1444
media_dir = MediaDir.NULL
1449
def __init__(self, lib=None, ci=None):
1451
self._cvt_from_pjsua(lib, ci)
1453
def _cvt_from_pjsua(self, lib, ci):
1455
self.account = lib._lookup_account(ci.acc_id)
1456
self.uri = ci.local_info
1457
self.contact = ci.local_contact
1458
self.remote_uri = ci.remote_info
1459
self.remote_contact = ci.remote_contact
1460
self.sip_call_id = ci.call_id
1461
self.state = ci.state
1462
self.state_text = ci.state_text
1463
self.last_code = ci.last_status
1464
self.last_reason = ci.last_status_text
1465
self.media_state = ci.media_status
1466
self.media_dir = ci.media_dir
1467
self.conf_slot = ci.conf_slot
1468
self.call_time = ci.connect_duration / 1000
1469
self.total_time = ci.total_duration / 1000
1473
"""This class represents SIP call.
1475
Application initiates outgoing call with Account.make_call(), and
1476
incoming calls are reported in AccountCallback.on_incoming_call().
1483
def __init__(self, lib, call_id, cb=None):
1484
self._lib = weakref.ref(lib)
1485
self.set_callback(cb)
1486
self.attach_to_id(call_id)
1487
_Trace((self, 'created'))
1491
_pjsua.call_set_user_data(self._id, 0)
1492
_Trace((self, 'destroyed'))
1495
return self._obj_name
1497
def attach_to_id(self, call_id):
1498
lck = self._lib().auto_lock()
1500
_pjsua.call_set_user_data(self._id, 0)
1503
_pjsua.call_set_user_data(self._id, self)
1504
self._obj_name = "{Call " + self.info().remote_uri + "}"
1506
self._obj_name = "{Call object}"
1508
def set_callback(self, cb):
1510
Set callback object to retrieve event notifications from this call.
1513
cb -- CallCallback instance.
1518
self._cb = CallCallback(self)
1519
self._cb._set_call(self)
1525
lck = self._lib().auto_lock()
1526
ci = _pjsua.call_get_info(self._id)
1528
self._lib()._err_check("info", self, -1, "Invalid call")
1529
call_info = CallInfo(self._lib(), ci)
1534
Check if this call is still valid.
1536
lck = self._lib().auto_lock()
1537
return _pjsua.call_is_active(self._id)
1539
def dump_status(self, with_media=True, indent="", max_len=1024):
1541
Dump the call status.
1543
lck = self._lib().auto_lock()
1544
return _pjsua.call_dump(self._id, with_media, max_len, indent)
1546
def answer(self, code=200, reason="", hdr_list=None):
1548
Send provisional or final response to incoming call.
1551
code -- SIP status code.
1552
reason -- Reason phrase. Put empty to send default reason
1553
phrase for the status code.
1554
hdr_list -- Optional list of headers to be sent with the
1558
lck = self._lib().auto_lock()
1559
err = _pjsua.call_answer(self._id, code, reason,
1560
Lib._create_msg_data(hdr_list))
1561
self._lib()._err_check("answer()", self, err)
1563
def hangup(self, code=603, reason="", hdr_list=None):
1568
code -- SIP status code.
1569
reason -- Reason phrase. Put empty to send default reason
1570
phrase for the status code.
1571
hdr_list -- Optional list of headers to be sent with the
1575
lck = self._lib().auto_lock()
1576
err = _pjsua.call_hangup(self._id, code, reason,
1577
Lib._create_msg_data(hdr_list))
1578
self._lib()._err_check("hangup()", self, err)
1580
def hold(self, hdr_list=None):
1582
Put the call on hold.
1585
hdr_list -- Optional list of headers to be sent with the
1588
lck = self._lib().auto_lock()
1589
err = _pjsua.call_set_hold(self._id, Lib._create_msg_data(hdr_list))
1590
self._lib()._err_check("hold()", self, err)
1592
def unhold(self, hdr_list=None):
1594
Release the call from hold.
1597
hdr_list -- Optional list of headers to be sent with the
1601
lck = self._lib().auto_lock()
1602
err = _pjsua.call_reinvite(self._id, True,
1603
Lib._create_msg_data(hdr_list))
1604
self._lib()._err_check("unhold()", self, err)
1606
def reinvite(self, hdr_list=None):
1608
Send re-INVITE and optionally offer new codecs to use.
1611
hdr_list -- Optional list of headers to be sent with the
1615
lck = self._lib().auto_lock()
1616
err = _pjsua.call_reinvite(self._id, True,
1617
Lib._create_msg_data(hdr_list))
1618
self._lib()._err_check("reinvite()", self, err)
1620
def update(self, hdr_list=None, options=0):
1622
Send UPDATE and optionally offer new codecs to use.
1625
hdr_list -- Optional list of headers to be sent with the
1627
options -- Must be zero for now.
1630
lck = self._lib().auto_lock()
1631
err = _pjsua.call_update(self._id, options,
1632
Lib._create_msg_data(hdr_list))
1633
self._lib()._err_check("update()", self, err)
1635
def transfer(self, dest_uri, hdr_list=None):
1637
Transfer the call to new destination.
1640
dest_uri -- Specify the SIP URI to transfer the call to.
1641
hdr_list -- Optional list of headers to be sent with the
1645
lck = self._lib().auto_lock()
1646
err = _pjsua.call_xfer(self._id, dest_uri,
1647
Lib._create_msg_data(hdr_list))
1648
self._lib()._err_check("transfer()", self, err)
1650
def transfer_to_call(self, call, hdr_list=None, options=0):
1652
Attended call transfer.
1655
call -- The Call object to transfer call to.
1656
hdr_list -- Optional list of headers to be sent with the
1658
options -- Must be zero for now.
1661
lck = self._lib().auto_lock()
1662
err = _pjsua.call_xfer_replaces(self._id, call._id, options,
1663
Lib._create_msg_data(hdr_list))
1664
self._lib()._err_check("transfer_to_call()", self, err)
1666
def dial_dtmf(self, digits):
1668
Send DTMF digits with RTP event package.
1671
digits -- DTMF digit string.
1674
lck = self._lib().auto_lock()
1675
err = _pjsua.call_dial_dtmf(self._id, digits)
1676
self._lib()._err_check("dial_dtmf()", self, err)
1678
def send_request(self, method, hdr_list=None, content_type=None,
1681
Send arbitrary request to remote call.
1683
This is useful for example to send INFO request. Note that this
1684
function should not be used to send request that will change the
1685
call state such as CANCEL or BYE.
1688
method -- SIP method name.
1689
hdr_list -- Optional header list to be sent with the request.
1690
content_type -- Content type to describe the body, if the body
1692
body -- Optional SIP message body.
1695
lck = self._lib().auto_lock()
1696
if hdr_list or body:
1697
msg_data = _pjsua.Msg_Data()
1699
msg_data.hdr_list = hdr_list
1701
msg_data.content_type = content_type
1703
msg_data.msg_body = body
1707
err = _pjsua.call_send_request(self._id, method, msg_data)
1708
self._lib()._err_check("send_request()", self, err)
1710
def send_pager(self, text, im_id=0, content_type="text/plain",
1712
"""Send instant message inside a call.
1715
text -- Instant message to be sent
1716
im_id -- Optional instant message ID to identify this
1717
instant message when delivery status callback
1719
content_type -- MIME type identifying the instant message
1720
hdr_list -- Optional list of headers to be sent with the
1724
lck = self._lib().auto_lock()
1725
err = _pjsua.call_send_im(self._id, \
1726
content_type, text, \
1727
Lib._create_msg_data(hdr_list), \
1729
self._lib()._err_check("send_pager()", self, err)
1733
"""This class contains information about Buddy. Application may
1734
retrieve this information by calling Buddy.info().
1736
Member documentation:
1738
uri -- the Buddy URI.
1739
contact -- the Buddy Contact URI, if available.
1740
online_status -- the presence online status.
1741
online_text -- the presence online status text.
1742
activity -- the PresenceActivity
1743
subscribed -- specify whether buddy's presence status is currently
1745
sub_state -- SubscriptionState
1746
sub_term_reason -- The termination reason string of the last presence
1747
subscription to this buddy, if any.
1753
activity = PresenceActivity.UNKNOWN
1755
sub_state = SubscriptionState.NULL
1756
sub_term_reason = ""
1758
def __init__(self, pjsua_bi=None):
1760
self._cvt_from_pjsua(pjsua_bi)
1762
def _cvt_from_pjsua(self, inf):
1764
self.contact = inf.contact
1765
self.online_status = inf.status
1766
self.online_text = inf.status_text
1767
self.activity = inf.activity
1768
self.subscribed = inf.monitor_pres
1769
self.sub_state = inf.sub_state
1770
self.sub_term_reason = inf.sub_term_reason
1773
class BuddyCallback:
1774
"""This class can be used to receive notifications about Buddy's
1775
presence status change. Application needs to derive a class from
1776
this class, and register the instance with Buddy.set_callback().
1778
Member documentation:
1780
buddy -- the Buddy object.
1784
def __init__(self, buddy=None):
1785
self._set_buddy(buddy)
1787
def _set_buddy(self, buddy):
1789
self.buddy = weakref.proxy(buddy)
1795
Notification that buddy's presence state has changed. Application
1796
may then retrieve the new status with Buddy.info() function.
1800
def on_pager(self, mime_type, body):
1801
"""Notification that incoming instant message is received from
1805
mime_type -- MIME type of the instant message body
1806
body -- the instant message body
1811
def on_pager_status(self, body, im_id, code, reason):
1812
"""Notification about the delivery status of previously sent
1816
body -- the message body
1818
code -- SIP status code
1819
reason -- SIP reason phrase
1824
def on_typing(self, is_typing):
1825
"""Notification that remote is typing or stop typing.
1828
is_typing -- boolean to indicate whether remote is currently
1829
typing an instant message.
1836
"""A Buddy represents person or remote agent.
1838
This class provides functions to subscribe to buddy's presence and
1839
to send or receive instant messages from the buddy.
1847
def __init__(self, lib, id, account, cb):
1849
self._lib = weakref.ref(lib)
1850
self._acc = weakref.ref(account)
1851
self._obj_name = "{Buddy " + self.info().uri + "}"
1852
self.set_callback(cb)
1853
_pjsua.buddy_set_user_data(self._id, self)
1854
_Trace((self, 'created'))
1858
_pjsua.buddy_set_user_data(self._id, 0)
1859
_Trace((self, 'destroyed'))
1862
return self._obj_name
1866
Get buddy info as BuddyInfo.
1868
lck = self._lib().auto_lock()
1869
return BuddyInfo(_pjsua.buddy_get_info(self._id))
1871
def set_callback(self, cb):
1872
"""Install callback to receive notifications from this object.
1875
cb -- BuddyCallback instance.
1880
self._cb = BuddyCallback(self)
1881
self._cb._set_buddy(self)
1883
def subscribe(self):
1885
Subscribe to buddy's presence status notification.
1887
lck = self._lib().auto_lock()
1888
err = _pjsua.buddy_subscribe_pres(self._id, True)
1889
self._lib()._err_check("subscribe()", self, err)
1891
def unsubscribe(self):
1893
Unsubscribe from buddy's presence status notification.
1895
lck = self._lib().auto_lock()
1896
err = _pjsua.buddy_subscribe_pres(self._id, False)
1897
self._lib()._err_check("unsubscribe()", self, err)
1901
Remove this buddy from the buddy list.
1903
lck = self._lib().auto_lock()
1905
_pjsua.buddy_set_user_data(self._id, 0)
1906
err = _pjsua.buddy_del(self._id)
1907
self._lib()._err_check("delete()", self, err)
1909
def send_pager(self, text, im_id=0, content_type="text/plain", \
1911
"""Send instant message to remote buddy.
1914
text -- Instant message to be sent
1915
im_id -- Optional instant message ID to identify this
1916
instant message when delivery status callback
1918
content_type -- MIME type identifying the instant message
1919
hdr_list -- Optional list of headers to be sent with the
1923
lck = self._lib().auto_lock()
1924
err = _pjsua.im_send(self._acc()._id, self.info().uri, \
1925
content_type, text, \
1926
Lib._create_msg_data(hdr_list), \
1928
self._lib()._err_check("send_pager()", self, err)
1930
def send_typing_ind(self, is_typing=True, hdr_list=None):
1931
"""Send typing indication to remote buddy.
1934
is_typing -- boolean to indicate wheter user is typing.
1935
hdr_list -- Optional list of headers to be sent with the
1939
lck = self._lib().auto_lock()
1940
err = _pjsua.im_typing(self._acc()._id, self.info().uri, \
1941
is_typing, Lib._create_msg_data(hdr_list))
1942
self._lib()._err_check("send_typing_ind()", self, err)
1947
class SoundDeviceInfo:
1948
"""This described the sound device info.
1950
Member documentation:
1951
name -- device name.
1952
input_channels -- number of capture channels supported.
1953
output_channels -- number of playback channels supported.
1954
default_clock_rate -- default sampling rate.
1959
default_clock_rate = 0
1961
def __init__(self, sdi):
1962
self.name = sdi.name
1963
self.input_channels = sdi.input_count
1964
self.output_channels = sdi.output_count
1965
self.default_clock_rate = sdi.default_samples_per_sec
1970
"""This describes codec info.
1972
Member documentation:
1974
priority -- codec priority (0-255)
1975
clock_rate -- clock rate
1976
channel_count -- number of channels
1977
avg_bps -- average bandwidth in bits per second
1978
frm_ptime -- base frame length in milliseconds
1979
ptime -- RTP frame length in milliseconds.
1981
vad_enabled -- specify if Voice Activity Detection is currently
1983
plc_enabled -- specify if Packet Lost Concealment is currently
1997
def __init__(self, codec_info, codec_param):
1998
self.name = codec_info.codec_id
1999
self.priority = codec_info.priority
2000
self.clock_rate = codec_param.info.clock_rate
2001
self.channel_count = codec_param.info.channel_cnt
2002
self.avg_bps = codec_param.info.avg_bps
2003
self.frm_ptime = codec_param.info.frm_ptime
2004
self.ptime = codec_param.info.frm_ptime * \
2005
codec_param.setting.frm_per_pkt
2006
self.ptime = codec_param.info.pt
2007
self.vad_enabled = codec_param.setting.vad
2008
self.plc_enabled = codec_param.setting.plc
2010
def _cvt_to_pjsua(self):
2011
ci = _pjsua.Codec_Info()
2012
ci.codec_id = self.name
2013
ci.priority = self.priority
2018
class CodecParameter:
2019
"""This specifies various parameters that can be configured for codec.
2021
Member documentation:
2023
ptime -- specify the outgoing RTP packet length in milliseconds.
2024
vad_enabled -- specify if VAD should be enabled.
2025
plc_enabled -- specify if PLC should be enabled.
2032
def __init__(self, codec_param):
2033
self.ptime = codec_param.info.frm_ptime * \
2034
codec_param.setting.frm_per_pkt
2035
self.vad_enabled = codec_param.setting.vad
2036
self.plc_enabled = codec_param.setting.plc
2037
self._codec_param = codec_param
2039
def _cvt_to_pjsua(self):
2040
self._codec_param.setting.frm_per_pkt = self.ptime / \
2041
self._codec_param.info.frm_ptime
2042
self._codec_param.setting.vad = self.vad_enabled
2043
self._codec_param.setting.plc = self.plc_enabled
2044
return self._codec_param
2049
def __init__(self, lck):
2052
#_Trace(('lock acquired',))
2057
#_Trace(('lock released',))
2059
#_Trace(('lock release error',))
2065
enable_trace = False
2068
"""Library instance.
2078
raise Error("__init()__", None, -1,
2079
"Library instance already exist")
2081
self._lock = threading.RLock()
2082
err = _pjsua.create()
2083
self._err_check("_pjsua.create()", None, err)
2089
_Trace(('Lib destroyed',))
2096
"""Return singleton instance of Lib.
2100
def init(self, ua_cfg=None, log_cfg=None, media_cfg=None):
2102
Initialize pjsua with the specified configurations.
2105
ua_cfg -- optional UAConfig instance
2106
log_cfg -- optional LogConfig instance
2107
media_cfg -- optional MediaConfig instance
2110
if not ua_cfg: ua_cfg = UAConfig()
2111
if not log_cfg: log_cfg = LogConfig()
2112
if not media_cfg: media_cfg = MediaConfig()
2114
py_ua_cfg = ua_cfg._cvt_to_pjsua()
2115
py_ua_cfg.cb.on_call_state = _cb_on_call_state
2116
py_ua_cfg.cb.on_incoming_call = _cb_on_incoming_call
2117
py_ua_cfg.cb.on_call_media_state = _cb_on_call_media_state
2118
py_ua_cfg.cb.on_dtmf_digit = _cb_on_dtmf_digit
2119
py_ua_cfg.cb.on_call_transfer_request = _cb_on_call_transfer_request
2120
py_ua_cfg.cb.on_call_transfer_status = _cb_on_call_transfer_status
2121
py_ua_cfg.cb.on_call_replace_request = _cb_on_call_replace_request
2122
py_ua_cfg.cb.on_call_replaced = _cb_on_call_replaced
2123
py_ua_cfg.cb.on_reg_state = _cb_on_reg_state
2124
py_ua_cfg.cb.on_incoming_subscribe = _cb_on_incoming_subscribe
2125
py_ua_cfg.cb.on_buddy_state = _cb_on_buddy_state
2126
py_ua_cfg.cb.on_pager = _cb_on_pager
2127
py_ua_cfg.cb.on_pager_status = _cb_on_pager_status
2128
py_ua_cfg.cb.on_typing = _cb_on_typing
2129
py_ua_cfg.cb.on_mwi_info = _cb_on_mwi_info;
2131
err = _pjsua.init(py_ua_cfg, log_cfg._cvt_to_pjsua(),
2132
media_cfg._cvt_to_pjsua())
2133
self._err_check("init()", self, err)
2136
"""Destroy the library, and pjsua."""
2138
if self._has_thread:
2141
while self._quit != 2 and loop < 400:
2142
self.handle_events(5)
2148
def start(self, with_thread=True):
2149
"""Start the library.
2152
with_thread -- specify whether the module should create worker
2156
lck = self.auto_lock()
2157
err = _pjsua.start()
2158
self._err_check("start()", self, err)
2159
self._has_thread = with_thread
2160
if self._has_thread:
2161
thread.start_new(_worker_thread_main, (0,))
2163
def handle_events(self, timeout=50):
2164
"""Poll the events from underlying pjsua library.
2166
Application must poll the stack periodically if worker thread
2167
is disable when starting the library.
2170
timeout -- in milliseconds.
2173
lck = self.auto_lock()
2174
return _pjsua.handle_events(timeout)
2176
def thread_register(self, name):
2177
"""Register external threads (threads that are not created by PJSIP,
2178
such as threads that are created by Python API) to PJSIP.
2180
The call must be made from the new thread before calling any pjlib
2184
name -- Non descriptive name for the thread
2187
err = _pjsua.thread_register(name, dummy)
2188
self._err_check("thread_register()", self, err)
2190
def verify_sip_url(self, sip_url):
2191
"""Verify that the specified string is a valid URI.
2194
sip_url -- the URL string.
2197
0 is the the URI is valid, otherwise the appropriate error
2201
lck = self.auto_lock()
2202
return _pjsua.verify_sip_url(sip_url)
2204
def create_transport(self, type, cfg=None):
2205
"""Create SIP transport instance of the specified type.
2208
type -- transport type from TransportType constant.
2209
cfg -- TransportConfig instance
2215
lck = self.auto_lock()
2216
if not cfg: cfg=TransportConfig()
2217
err, tp_id = _pjsua.transport_create(type, cfg._cvt_to_pjsua())
2218
self._err_check("create_transport()", self, err)
2219
return Transport(self, tp_id)
2221
def create_account(self, acc_config, set_default=True, cb=None):
2223
Create a new local pjsua account using the specified configuration.
2226
acc_config -- AccountConfig
2227
set_default -- boolean to specify whether to use this as the
2229
cb -- AccountCallback instance.
2235
lck = self.auto_lock()
2236
err, acc_id = _pjsua.acc_add(acc_config._cvt_to_pjsua(), set_default)
2237
self._err_check("create_account()", self, err)
2238
return Account(self, acc_id, cb)
2240
def create_account_for_transport(self, transport, set_default=True,
2242
"""Create a new local pjsua transport for the specified transport.
2245
transport -- the Transport instance.
2246
set_default -- boolean to specify whether to use this as the
2248
cb -- AccountCallback instance.
2254
lck = self.auto_lock()
2255
err, acc_id = _pjsua.acc_add_local(transport._id, set_default)
2256
self._err_check("create_account_for_transport()", self, err)
2257
return Account(self, acc_id, cb)
2259
def hangup_all(self):
2260
"""Hangup all calls.
2263
lck = self.auto_lock()
2264
_pjsua.call_hangup_all()
2268
def enum_snd_dev(self):
2269
"""Enumerate sound devices in the system.
2272
list of SoundDeviceInfo. The index of the element specifies
2273
the device ID for the device.
2275
lck = self.auto_lock()
2276
sdi_list = _pjsua.enum_snd_devs()
2278
for sdi in sdi_list:
2279
info.append(SoundDeviceInfo(sdi))
2282
def get_snd_dev(self):
2283
"""Get the device IDs of current sound devices used by pjsua.
2286
(capture_dev_id, playback_dev_id) tuple
2288
lck = self.auto_lock()
2289
return _pjsua.get_snd_dev()
2291
def set_snd_dev(self, capture_dev, playback_dev):
2292
"""Change the current sound devices.
2295
capture_dev -- the device ID of capture device to be used
2296
playback_dev -- the device ID of playback device to be used.
2299
lck = self.auto_lock()
2300
err = _pjsua.set_snd_dev(capture_dev, playback_dev)
2301
self._err_check("set_current_sound_devices()", self, err)
2303
def set_null_snd_dev(self):
2304
"""Disable the sound devices. This is useful if the system
2305
does not have sound device installed.
2308
lck = self.auto_lock()
2309
err = _pjsua.set_null_snd_dev()
2310
self._err_check("set_null_snd_dev()", self, err)
2315
def conf_get_max_ports(self):
2316
"""Get the conference bridge capacity.
2319
conference bridge capacity.
2322
lck = self.auto_lock()
2323
return _pjsua.conf_get_max_ports()
2325
def conf_connect(self, src_slot, dst_slot):
2326
"""Establish unidirectional media flow from souce to sink.
2328
One source may transmit to multiple destinations/sink. And if
2329
multiple sources are transmitting to the same sink, the media
2330
will be mixed together. Source and sink may refer to the same ID,
2331
effectively looping the media.
2333
If bidirectional media flow is desired, application needs to call
2334
this function twice, with the second one having the arguments
2338
src_slot -- integer to identify the conference slot number of
2339
the source/transmitter.
2340
dst_slot -- integer to identify the conference slot number of
2341
the destination/receiver.
2344
lck = self.auto_lock()
2345
err = _pjsua.conf_connect(src_slot, dst_slot)
2346
self._err_check("conf_connect()", self, err)
2348
def conf_disconnect(self, src_slot, dst_slot):
2349
"""Disconnect media flow from the source to destination port.
2352
src_slot -- integer to identify the conference slot number of
2353
the source/transmitter.
2354
dst_slot -- integer to identify the conference slot number of
2355
the destination/receiver.
2358
lck = self.auto_lock()
2359
err = _pjsua.conf_disconnect(src_slot, dst_slot)
2360
self._err_check("conf_disconnect()", self, err)
2362
def conf_set_tx_level(self, slot, level):
2363
"""Adjust the signal level to be transmitted from the bridge to
2364
the specified port by making it louder or quieter.
2367
slot -- integer to identify the conference slot number.
2368
level -- Signal level adjustment. Value 1.0 means no level
2369
adjustment, while value 0 means to mute the port.
2371
lck = self.auto_lock()
2372
err = _pjsua.conf_set_tx_level(slot, level)
2373
self._err_check("conf_set_tx_level()", self, err)
2375
def conf_set_rx_level(self, slot, level):
2376
"""Adjust the signal level to be received from the specified port
2377
(to the bridge) by making it louder or quieter.
2380
slot -- integer to identify the conference slot number.
2381
level -- Signal level adjustment. Value 1.0 means no level
2382
adjustment, while value 0 means to mute the port.
2384
lck = self.auto_lock()
2385
err = _pjsua.conf_set_rx_level(slot, level)
2386
self._err_check("conf_set_rx_level()", self, err)
2388
def conf_get_signal_level(self, slot):
2389
"""Get last signal level transmitted to or received from the
2390
specified port. The signal levels are float values from 0.0 to 1.0,
2391
with 0.0 indicates no signal, and 1.0 indicates the loudest signal
2395
slot -- integer to identify the conference slot number.
2398
(tx_level, rx_level) tuple.
2400
lck = self.auto_lock()
2401
err, tx_level, rx_level = _pjsua.conf_get_signal_level(slot)
2402
self._err_check("conf_get_signal_level()", self, err)
2403
return (tx_level, rx_level)
2409
def enum_codecs(self):
2410
"""Return list of codecs supported by pjsua.
2416
lck = self.auto_lock()
2417
ci_list = _pjsua.enum_codecs()
2420
cp = _pjsua.codec_get_param(ci.codec_id)
2422
codec_info.append(CodecInfo(ci, cp))
2425
def set_codec_priority(self, name, priority):
2426
"""Change the codec priority.
2430
priority -- Codec priority, which range is 0-255.
2433
lck = self.auto_lock()
2434
err = _pjsua.codec_set_priority(name, priority)
2435
self._err_check("set_codec_priority()", self, err)
2437
def get_codec_parameter(self, name):
2438
"""Get codec parameter for the specified codec.
2444
lck = self.auto_lock()
2445
cp = _pjsua.codec_get_param(name)
2447
self._err_check("get_codec_parameter()", self, -1,
2448
"Invalid codec name")
2449
return CodecParameter(cp)
2451
def set_codec_parameter(self, name, param):
2452
"""Modify codec parameter for the specified codec.
2456
param -- codec parameter.
2459
lck = self.auto_lock()
2460
err = _pjsua.codec_set_param(name, param._cvt_to_pjsua())
2461
self._err_check("set_codec_parameter()", self, err)
2463
# WAV playback and recording
2465
def create_player(self, filename, loop=False):
2466
"""Create WAV file player.
2469
filename -- WAV file name
2470
loop -- boolean to specify whether playback should
2471
automatically restart upon EOF
2476
lck = self.auto_lock()
2480
err, player_id = _pjsua.player_create(filename, opt)
2481
self._err_check("create_player()", self, err)
2484
def player_get_slot(self, player_id):
2485
"""Get the conference port ID for the specified player.
2488
player_id -- the WAV player ID
2491
Conference slot number for the player
2494
lck = self.auto_lock()
2495
slot = _pjsua.player_get_conf_port(player_id)
2497
self._err_check("player_get_slot()", self, -1,
2498
"Invalid player id")
2501
def player_set_pos(self, player_id, pos):
2502
"""Set WAV playback position.
2505
player_id -- WAV player ID
2506
pos -- playback position, in samples
2509
lck = self.auto_lock()
2510
err = _pjsua.player_set_pos(player_id, pos)
2511
self._err_check("player_set_pos()", self, err)
2513
def player_destroy(self, player_id):
2514
"""Destroy the WAV player.
2517
player_id -- the WAV player ID.
2520
lck = self.auto_lock()
2521
err = _pjsua.player_destroy(player_id)
2522
self._err_check("player_destroy()", self, err)
2524
def create_playlist(self, filelist, label="playlist", loop=True):
2525
"""Create WAV playlist.
2528
filelist -- List of WAV file names.
2529
label -- Optional name to be assigned to the playlist
2530
object (useful for logging)
2531
loop -- boolean to specify whether playback should
2532
automatically restart upon EOF
2537
lck = self.auto_lock()
2541
err, playlist_id = _pjsua.playlist_create(label, filelist, opt)
2542
self._err_check("create_playlist()", self, err)
2545
def playlist_get_slot(self, playlist_id):
2546
"""Get the conference port ID for the specified playlist.
2549
playlist_id -- the WAV playlist ID
2552
Conference slot number for the playlist
2555
lck = self.auto_lock()
2556
slot = _pjsua.player_get_conf_port(playlist_id)
2558
self._err_check("playlist_get_slot()", self, -1,
2559
"Invalid playlist id")
2562
def playlist_destroy(self, playlist_id):
2563
"""Destroy the WAV playlist.
2566
playlist_id -- the WAV playlist ID.
2569
lck = self.auto_lock()
2570
err = _pjsua.player_destroy(playlist_id)
2571
self._err_check("playlist_destroy()", self, err)
2573
def create_recorder(self, filename):
2574
"""Create WAV file recorder.
2577
filename -- WAV file name
2583
lck = self.auto_lock()
2584
err, rec_id = _pjsua.recorder_create(filename, 0, None, -1, 0)
2585
self._err_check("create_recorder()", self, err)
2588
def recorder_get_slot(self, rec_id):
2589
"""Get the conference port ID for the specified recorder.
2592
rec_id -- the WAV recorder ID
2595
Conference slot number for the recorder
2598
lck = self.auto_lock()
2599
slot = _pjsua.recorder_get_conf_port(rec_id)
2601
self._err_check("recorder_get_slot()", self, -1,
2602
"Invalid recorder id")
2605
def recorder_destroy(self, rec_id):
2606
"""Destroy the WAV recorder.
2609
rec_id -- the WAV recorder ID.
2612
lck = self.auto_lock()
2613
err = _pjsua.recorder_destroy(rec_id)
2614
self._err_check("recorder_destroy()", self, err)
2617
# Internal functions
2621
return _pjsua.strerror(err)
2623
def _err_check(self, op_name, obj, err_code, err_msg=""):
2625
raise Error(op_name, obj, err_code, err_msg)
2628
def _create_msg_data(hdr_list):
2631
msg_data = _pjsua.Msg_Data()
2632
msg_data.hdr_list = hdr_list
2635
def auto_lock(self):
2636
return _LibMutex(self._lock)
2638
# Internal dictionary manipulation for calls, accounts, and buddies
2640
def _lookup_call(self, call_id):
2641
return _pjsua.call_get_user_data(call_id)
2643
def _lookup_account(self, acc_id):
2644
return _pjsua.acc_get_user_data(acc_id)
2646
def _lookup_buddy(self, buddy_id, uri=None):
2648
buddy = _pjsua.buddy_get_user_data(buddy_id)
2650
buddy_id = _pjsua.buddy_find(uri)
2652
buddy = _pjsua.buddy_get_user_data(buddy_id)
2662
def _cb_on_reg_state(self, acc_id):
2663
acc = self._lookup_account(acc_id)
2665
acc._cb.on_reg_state()
2667
def _cb_on_incoming_subscribe(self, acc_id, buddy_id, from_uri,
2668
contact_uri, pres_obj):
2669
acc = self._lookup_account(acc_id)
2671
buddy = self._lookup_buddy(buddy_id)
2672
return acc._cb.on_incoming_subscribe(buddy, from_uri, contact_uri,
2677
def _cb_on_incoming_call(self, acc_id, call_id, rdata):
2678
acc = self._lookup_account(acc_id)
2680
acc._cb.on_incoming_call( Call(self, call_id) )
2682
_pjsua.call_hangup(call_id, 603, None, None)
2686
def _cb_on_call_state(self, call_id):
2687
call = self._lookup_call(call_id)
2690
call.attach_to_id(call_id)
2691
done = (call.info().state == CallState.DISCONNECTED)
2694
_pjsua.call_set_user_data(call_id, 0)
2698
def _cb_on_call_media_state(self, call_id):
2699
call = self._lookup_call(call_id)
2701
call._cb.on_media_state()
2703
def _cb_on_dtmf_digit(self, call_id, digits):
2704
call = self._lookup_call(call_id)
2706
call._cb.on_dtmf_digit(digits)
2708
def _cb_on_call_transfer_request(self, call_id, dst, code):
2709
call = self._lookup_call(call_id)
2711
return call._cb.on_transfer_request(dst, code)
2715
def _cb_on_call_transfer_status(self, call_id, code, text, final, cont):
2716
call = self._lookup_call(call_id)
2718
return call._cb.on_transfer_status(code, text, final, cont)
2722
def _cb_on_call_replace_request(self, call_id, rdata, code, reason):
2723
call = self._lookup_call(call_id)
2725
return call._cb.on_replace_request(code, reason)
2729
def _cb_on_call_replaced(self, old_call_id, new_call_id):
2730
old_call = self._lookup_call(old_call_id)
2731
new_call = self._lookup_call(new_call_id)
2732
if old_call and new_call:
2733
old_call._cb.on_replaced(new_call)
2735
def _cb_on_pager(self, call_id, from_uri, to_uri, contact, mime_type,
2739
call = self._lookup_call(call_id)
2741
call._cb.on_pager(mime_type, body)
2743
acc = self._lookup_account(acc_id)
2744
buddy = self._lookup_buddy(-1, from_uri)
2746
buddy._cb.on_pager(mime_type, body)
2748
acc._cb.on_pager(from_uri, contact, mime_type, body)
2750
def _cb_on_pager_status(self, call_id, to_uri, body, user_data,
2751
code, reason, acc_id):
2754
call = self._lookup_call(call_id)
2756
call._cb.on_pager_status(body, user_data, code, reason)
2758
acc = self._lookup_account(acc_id)
2759
buddy = self._lookup_buddy(-1, to_uri)
2761
buddy._cb.on_pager_status(body, user_data, code, reason)
2763
acc._cb.on_pager_status(to_uri, body, user_data, code, reason)
2765
def _cb_on_typing(self, call_id, from_uri, to_uri, contact, is_typing,
2769
call = self._lookup_call(call_id)
2771
call._cb.on_typing(is_typing)
2773
acc = self._lookup_account(acc_id)
2774
buddy = self._lookup_buddy(-1, from_uri)
2776
buddy._cb.on_typing(is_typing)
2778
acc._cb.on_typing(from_uri, contact, is_typing)
2780
def _cb_on_mwi_info(self, acc_id, body):
2781
acc = self._lookup_account(acc_id)
2783
return acc._cb.on_mwi_info(body)
2785
def _cb_on_buddy_state(self, buddy_id):
2786
buddy = self._lookup_buddy(buddy_id)
2788
buddy._cb.on_state()
2794
def _cb_on_call_state(call_id, e):
2795
_lib._cb_on_call_state(call_id)
2797
def _cb_on_incoming_call(acc_id, call_id, rdata):
2798
_lib._cb_on_incoming_call(acc_id, call_id, rdata)
2800
def _cb_on_call_media_state(call_id):
2801
_lib._cb_on_call_media_state(call_id)
2803
def _cb_on_dtmf_digit(call_id, digits):
2804
_lib._cb_on_dtmf_digit(call_id, digits)
2806
def _cb_on_call_transfer_request(call_id, dst, code):
2807
return _lib._cb_on_call_transfer_request(call_id, dst, code)
2809
def _cb_on_call_transfer_status(call_id, code, reason, final, cont):
2810
return _lib._cb_on_call_transfer_status(call_id, code, reason,
2812
def _cb_on_call_replace_request(call_id, rdata, code, reason):
2813
return _lib._cb_on_call_replace_request(call_id, rdata, code, reason)
2815
def _cb_on_call_replaced(old_call_id, new_call_id):
2816
_lib._cb_on_call_replaced(old_call_id, new_call_id)
2818
def _cb_on_reg_state(acc_id):
2819
_lib._cb_on_reg_state(acc_id)
2821
def _cb_on_incoming_subscribe(acc_id, buddy_id, from_uri, contact_uri, pres):
2822
return _lib._cb_on_incoming_subscribe(acc_id, buddy_id, from_uri,
2825
def _cb_on_buddy_state(buddy_id):
2826
_lib._cb_on_buddy_state(buddy_id)
2828
def _cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id):
2829
_lib._cb_on_pager(call_id, from_uri, to, contact, mime_type, body, acc_id)
2831
def _cb_on_pager_status(call_id, to, body, user_data, status, reason, acc_id):
2832
_lib._cb_on_pager_status(call_id, to, body, user_data,
2833
status, reason, acc_id)
2835
def _cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id):
2836
_lib._cb_on_typing(call_id, from_uri, to, contact, is_typing, acc_id)
2838
def _cb_on_mwi_info(acc_id, body):
2839
_lib._cb_on_mwi_info(acc_id, body)
2842
def _worker_thread_main(arg):
2844
_Trace(('worker thread started..',))
2846
err = _pjsua.thread_register("python worker", thread_desc)
2847
_lib._err_check("thread_register()", _lib, err)
2848
while _lib and _lib._quit == 0:
2849
_lib.handle_events(1)
2853
_Trace(('worker thread exited..',))