wiki:Python_SIP_Tutorial

Version 9 (modified by bennylp, 16 years ago) (diff)

--

Getting Started

This tutorial replaces the older py_pjsua tutorial.

What is it?

This is the new Python wrapper for 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 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 PJSUA API. This module is the successor of py_pjsua module which now has been deprecated.
pjsua module:
This is the higher level abstraction for 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 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.


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 pjsua.Error exception.

Lib Class

The Lib class provides the base API's to communicate with PJSUA-API and to create objects (such as Account and Transport).


Initializing the Library

Instantiate the library:

import pjsua as pj

lib = pj.Lib()

then initialize and start the library.

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 Lib class reference manual for more information.


Transport

Application needs to create one or more Transport objects before it can send or receive SIP messages:

try:
    udp = lib.create_transport(pj.TransportType.UDP)

except pj.Error, e:
    print "Error creating transport:", e


Accounts

Application must create at least one 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 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.


Creating Accounts

To create transport account:

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 AccountConfig, then create the account:

try:
    acc_cfg = pj.AccountConfig()
    acc_cfg.id = "sip:user@pjsip.org"
    acc_cfg.reg_uri = "sip:pjsip.org"
    acc_cfg.proxy = ["<sip:pjsip.org;lr>"]
    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:

try:
    acc = lib.create_account(pj.AccountConfig("pjsip.org", "username", "password"), True)

except pj.Error, e:
    print "Error creating account:", e


Getting Events from Account

Account object emits events such as incoming call and registration state.

To capture events from Account, first you need to derive your account callback class from AccountCallback class and implement the relevant callback methods:

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 Call object a little bit above, that will be explained later).

Then install the callback to Account object:

   acc_cb = MyAccountCallback(acc)
   acc.set_callback(acc_cb)


Account Sample Application

For a complete account sample application (including registration), please see source:pjproject/trunk/pjsip-apps/src/python/samples/registration.py


Calls

Creating Calls

Incoming call events are reported via AccountCallback's on_incoming_call() callback as shown above.

To make outgoing call:

    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 CallCallback object (see below).


Getting Events from Call

To retrieve events from a call, derive a class from 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:

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:

  call_cb = MyCallCallback(call)
  call.set_callback(call_cb)


Call Sample Application

For a complete call sample application, please see source:pjproject/trunk/pjsip-apps/src/python/samples/call.py


Presence and Instant Messaging

(The doc is TBD)

An 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 Buddy object using account's add_buddy() method. Changes in buddy's presence status will be reported via 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


Working with Media

The Lib class provides API to manage media, such as:

  • create WAV file player or recorder
  • manage conference bridge connections
  • manage codecs
  • etc.


Reference Documentation

Please see pjsua Python module documentation for reference.