= Getting Started = This tutorial replaces the older [wiki:Py_PJSUA py_pjsua] tutorial. == What is it? == This is the new Python wrapper for [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm PJSUA API] which is available in PJSIP version 0.9.5 and later. It is much easier to use, much more Python-ish, and it deprecates the old [wiki:Py_PJSUA py_pjsua] Python module. The Python wrapper is implemented in two modules: '''_pjsua''' module: :: This is the low-level C Python module which provides Python binding to [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm PJSUA API]. This module is the successor of [wiki:Py_PJSUA py_pjsua] module which now has been deprecated. '''pjsua''' module: :: This is the higher level abstraction for [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm PJSUA API]. It is object oriented and implemented purely on Python, on top of {{{_pjsua}}} module. Applications should use the '''pjsua''' module rather than '''_pjsua''' module, since it is easier to use and it is the module which API compatibility will be maintained between releases. You can find all the source codes in [source:pjproject/trunk/pjsip-apps/src/python pjproject/pjsip-apps/src/python] directory. == Building The Modules == Using Microsoft Visual Studio projects: * Open '''pjsip-apps.dsw''' from {{{pjsip-apps\build}}} directory. * Select '''python_pjsua''' project as the active project. * Build the project * The {{{_pjsua.pyd}}} Python module will be placed in {{{pjsip-apps\lib}}} directory. * Copy {{{_pjsua.pyd}}} and {{{pjsua.py}}} from {{{pjsip-apps\src\python}}} directory to Python's site_packages directory (see Python manual for this), or alternatively add the directories where these files reside to your {{{PYTHONPATH}}} environment variable. Using Python build script: * Go to {{{pjsip-apps/src/python}}} directory. * Run '''{{{'python ./setup.py build'}}}''' * The Python module will be placed in {{{build}}} directory inside current directory. * Alternatively run '''{{{'python ./setup.py install'}}}''' to install both '''_pjsua''' and '''pjsua''' modules to Python's site_packages directory. [[BR]] = Developing Python SIP Application = == Introduction == The pjsua module only contains few classes so it should be straightforward to use. == Error Handling == By convention, we use exceptions as means to report error. Operations which yields error will raise [http://www.pjsip.org/python/pjsua.htm#Error pjsua.Error] exception. == Lib Class == The [http://www.pjsip.org/python/pjsua.htm#Lib Lib] class provides the base API's to communicate with PJSUA-API and to create objects (such as [http://www.pjsip.org/python/pjsua.htm#Account Account] and [http://www.pjsip.org/python/pjsua.htm#Transport Transport]). [[BR]] ==== Initializing the Library ==== Instantiate the library: {{{ #!python import pjsua as pj lib = pj.Lib() }}} then initialize and start the library. {{{ #!python try: lib.init() lib.start() except pj.Error, e: print "Error initializing library:", e }}} Both the {{{init()}}} and {{{start()}}} methods above may be given additional parameters. Please see [http://www.pjsip.org/python/pjsua.htm#Lib Lib] class reference manual for more information. [[BR]] == Transport == Application needs to create one or more [http://www.pjsip.org/python/pjsua.htm#Transport Transport] objects before it can send or receive SIP messages: {{{ #!python try: udp = lib.create_transport(pj.TransportType.UDP) except pj.Error, e: print "Error creating transport:", e }}} [[BR]] == Accounts == Application must create at least one [http://www.pjsip.org/python/pjsua.htm#Account Account] before it can send and receive SIP messages. An account specifies the '''From:''' URI, so it's needed before you can send SIP messages. There are two types of accounts in pjsua: * real account: this is an account that can register to a SIP server * transport account: this corresponds to one [http://www.pjsip.org/python/pjsua.htm#Transport Transport]. So for example if we have created UDP transport which listens to {{{192.168.0.1:5080}}}, the transport account will have URI: "{{{sip:192.168.0.1:5080}}}" (rather than, say, "{{{sip:user@domain}}}"). There can be more than one accounts in an application. [[BR]] ==== Creating Accounts ==== To create transport account: {{{ #!python try: acc = lib.create_account_for_transport(udp) except pj.Error, e: print "Error creating UDP local account:", e }}} To create a real account account, first you must configure an [http://www.pjsip.org/python/pjsua.htm#AccountConfig AccountConfig], then create the account: {{{ #!python try: acc_cfg = pj.AccountConfig() acc_cfg.id = "sip:user@pjsip.org" acc_cfg.reg_uri = "sip:pjsip.org" acc_cfg.proxy = [""] acc_cfg.auth_cred = [pj.AuthCred("*", "user", "password")] acc = lib.create_account(acc_cfg, True) except pj.Error, e: print "Error creating account:", e }}} Alternatively, for typical account config like above, we can do like this: {{{ #!python try: acc = lib.create_account(pj.AccountConfig("pjsip.org", "username", "password"), True) except pj.Error, e: print "Error creating account:", e }}} [[BR]] ==== Getting Events from Account ==== [http://www.pjsip.org/python/pjsua.htm#Account Account] object emits events such as incoming call and registration state. To capture events from [http://www.pjsip.org/python/pjsua.htm#Account Account], first you need to derive your account callback class from [http://www.pjsip.org/python/pjsua.htm#AccountCallback AccountCallback] class and implement the relevant callback methods: {{{ #!python class MyAccountCallback(pj.AccountCallback): def __init__(self, account): pj.AccountCallback.__init__(self, account) def on_reg_state(self): print "Account", self.account.info().uri, print "registration status is", self.account.info().reg_reason def on_incoming_call(self, call): print "Incoming call from", call.info().remote_uri call.answer(200) }}} (Note: we've touched the [http://www.pjsip.org/python/pjsua.htm#Call Call] object a little bit above, that will be explained later). Then install the callback to [http://www.pjsip.org/python/pjsua.htm#Account Account] object: {{{ #!python acc_cb = MyAccountCallback(acc) acc.set_callback(acc_cb) }}} [[BR]] === Account Sample Application === For a complete account sample application (including registration), please see source:pjproject/trunk/pjsip-apps/src/python/samples/registration.py [[BR]] == Calls == ==== Creating Calls ==== Incoming call events are reported via [http://www.pjsip.org/python/pjsua.htm#AccountCallback AccountCallback]'s {{{on_incoming_call()}}} callback as shown above. To make outgoing call: {{{ #!python try: call = acc.make_call("sip:buddy@pjsip.org") except pj.Error, e: print "Error in making call:", e }}} Note that as with all PJSIP operations, the {{{make_call()}}} function is asynchronous; it will not block until the call is connected, but rather it will return immediately as soon as the initial INVITE request is sent. Application is then informed about the call completion via [http://www.pjsip.org/python/pjsua.htm#CallCallback CallCallback] object (see below). [[BR]] ==== Getting Events from Call ==== To retrieve events from a call, derive a class from [http://www.pjsip.org/python/pjsua.htm#CallCallback CallCallback] class and implement the methods that you want to be notified about. Normally at the very least you'd want to implement {{{on_state()}}} and {{{on_media_state()}}} methods: {{{ #!python class MyCallCallback(pj.CallCallback): def __init__(self, call): pj.CallCallback.__init__(self, call) def on_state(self): print "Call with", self.call.info().remote_uri, print "is", self.call.info().state_text def on_media_state(self): if self.call.info().media_state == pj.MediaState.ACTIVE: # Connect the call to sound device call_slot = self.call.info().conf_slot pj.Lib.instance().conf_connect(call_slot, 0) pj.Lib.instance().conf_connect(0, call_slot) print "Media is now active" else: print "Media is inactive" }}} Then install your callback to the call object: {{{ #!python call_cb = MyCallCallback(call) call.set_callback(call_cb) }}} [[BR]] === Call Sample Application === For a complete call sample application, please see source:pjproject/trunk/pjsip-apps/src/python/samples/call.py [[BR]] == Presence and Instant Messaging == (The doc is TBD) An [http://www.pjsip.org/python/pjsua.htm#Account Account] has a presence status associated with it, and when the presence status is changed (with {{{set_basic_status()}}} or {{{set_presence_status()}}}), the changes will be propagated to presence subscriber with using either PUBLISH or NOTIFY SIP methods. To subscribe to buddy's presence status, application creates [http://www.pjsip.org/python/pjsua.htm#Buddy Buddy] object using account's {{{add_buddy()}}} method. Changes in buddy's presence status will be reported via [http://www.pjsip.org/python/pjsua.htm#BuddyCallback BuddyCallback] class, which must be derived and then installed to the Buddy object. For a complete presence and instant messaging sample application, please see source:pjproject/trunk/pjsip-apps/src/python/samples/presence.py [[BR]] = Reference Documentation = Please see [http://www.pjsip.org/python/pjsua.htm pjsua] Python module documentation for reference.