8 | | '''[/repos/browser/pjproject/trunk/pjsip-apps/src/py_pjsua py_pjsua]''' is a Python module implemented in C language to provide '''[http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm PJSUA-API]''' for [http://www.python.org Python] applications. Using '''[/repos/browser/pjproject/trunk/pjsip-apps/src/py_pjsua py_pjsua]''' enables Python application to exploit the features of PJSIP, for example: |
9 | | * multiple SIP accounts |
10 | | * SIP for presence (SIMPLE) and instant messaging |
11 | | * multiple/unlimited calls |
12 | | * call hold and transfer (attended or unattended) |
13 | | * DTMF support |
14 | | * conferencing with multiple/unlimited sources |
15 | | * wideband and ultra-wideband audio support |
16 | | * WAV files playback, playlist, and recording |
17 | | * adaptive jitter buffer, silence detection, packet lost concealment, etc. |
18 | | * tone generation |
19 | | * multiple sound devices (planned) |
20 | | * ICE support (planned) |
21 | | * and so on. |
22 | | |
23 | | == Status == |
24 | | |
25 | | The '''py_pjsua''' module has just been released on 0.5.10 version and therefore it's expected to contain few bugs, so it's still in alpha/beta stage. |
26 | | |
27 | | Also since the Python abstraction is created manually (rather than using automated Python abstraction generation tools), it is expected that there will be time lag between introduction of new API in PJSUA-API (the C API) and the implementation in the Python module. |
28 | | |
29 | | |
30 | | == Building py_pjsua Module == |
| 9 | 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. |
| 10 | |
| 11 | The Python wrapper is implemented in two modules: |
| 12 | |
| 13 | '''_pjsua''' module :: |
| 14 | 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. |
| 15 | |
| 16 | '''pjsua''' module :: |
| 17 | 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. |
| 18 | |
| 19 | 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. |
| 20 | |
| 21 | You can find all the source codes in [source:pjproject/trunk/pjsip-apps/src/python pjproject/pjsip-apps/src/python] directory. |
| 22 | |
| 23 | |
| 24 | == Building The Modules == |
49 | | The Python API is pretty much the same like PJSUA-API - each Python function corresponds to one function in PJSUA-API, therefore one can use [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm PJSUA-API Documentation] or [wiki:PJSIP_Tutorial PJSUA Tutorial] to learn about the Python API. |
50 | | |
51 | | To highlight the similarities between PJSUA-API and the py_pjsua API, below are some sample names: |
52 | | |
53 | | {{{ |
54 | | PJSUA-API: py_pjsua API: |
55 | | |
56 | | #include <pjsua-lib/pjsua.h> ==> import py_pjsua |
57 | | |
58 | | pjsua_create() ==> py_pjsua.create() |
59 | | pjsua_init() ==> py_pjsua.init() |
60 | | |
61 | | pjsua_call_make_call() ==> py_pjsua.call_make_call() |
62 | | }}} |
63 | | |
64 | | |
65 | | |
66 | | |
67 | | == Sample Application == |
68 | | |
69 | | Please see [/repos/browser/pjproject/trunk/pjsip-apps/src/py_pjsua/pjsua_app.py pjsua_app.py] for a sample/simple Python application. |
70 | | |
71 | | |
72 | | == Documentation == |
73 | | |
74 | | The documentation for the Python module is integrated with '''[http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm PJSUA-API Documentation]'''. Please follow the step by step on how to use the API there, as well as specific instructions to use each PJSUA feature. |
75 | | |
| 46 | The pjsua module only contains few classes so it should be straightforward to use. |
| 47 | |
| 48 | === Error Handling === |
| 49 | |
| 50 | 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. |
| 51 | |
| 52 | |
| 53 | === Lib Class === |
| 54 | |
| 55 | 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]). |
| 56 | |
| 57 | ==== Initializing the Library ==== |
| 58 | |
| 59 | Instantiate the library: |
| 60 | |
| 61 | {{{ |
| 62 | #!python |
| 63 | |
| 64 | import pjsua as pj |
| 65 | |
| 66 | lib = pj.Lib() |
| 67 | |
| 68 | }}} |
| 69 | |
| 70 | then initialize and start the library. |
| 71 | |
| 72 | {{{ |
| 73 | #!python |
| 74 | |
| 75 | try: |
| 76 | lib.init() |
| 77 | lib.start() |
| 78 | |
| 79 | except pj.Error, e: |
| 80 | print "Error initializing library:", e |
| 81 | }}} |
| 82 | |
| 83 | 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. |
| 84 | |
| 85 | |
| 86 | === Transport === |
| 87 | |
| 88 | 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: |
| 89 | |
| 90 | {{{ |
| 91 | #!python |
| 92 | |
| 93 | try: |
| 94 | udp = lib.create_transport(pj.TransportType.UDP) |
| 95 | |
| 96 | except pj.Error, e: |
| 97 | print "Error creating transport:", e |
| 98 | }}} |
| 99 | |
| 100 | |
| 101 | === Accounts === |
| 102 | |
| 103 | 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. |
| 104 | |
| 105 | There are two types of accounts in pjsua: |
| 106 | * real account: this is an account that can register to a SIP server |
| 107 | * 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}}}"). |
| 108 | |
| 109 | There can be more than one accounts in an application. |
| 110 | |
| 111 | ==== Creating Accounts ==== |
| 112 | |
| 113 | To create transport account: |
| 114 | |
| 115 | {{{ |
| 116 | #!python |
| 117 | |
| 118 | try: |
| 119 | acc = lib.create_account_for_transport(udp) |
| 120 | |
| 121 | except pj.Error, e: |
| 122 | print "Error creating UDP local account:", e |
| 123 | }}} |
| 124 | |
| 125 | To create a real account account, first you must configure an [http://www.pjsip.org/python/pjsua.htm#AccountConfig AccountConfig], then create the account: |
| 126 | |
| 127 | {{{ |
| 128 | #!python |
| 129 | |
| 130 | try: |
| 131 | acc_cfg = pj.AccountConfig() |
| 132 | acc_cfg.id = "sip:user@pjsip.org" |
| 133 | acc_cfg.reg_uri = "sip:pjsip.org" |
| 134 | acc_cfg.proxy = ["<sip:pjsip.org;lr>"] |
| 135 | acc_cfg.auth_cred = [pj.AuthCred("*", "user", "password")] |
| 136 | |
| 137 | acc = lib.create_account(acc_cfg, True) |
| 138 | |
| 139 | except pj.Error, e: |
| 140 | print "Error creating account:", e |
| 141 | }}} |
| 142 | |
| 143 | Alternatively, for typical account config like above, we can do like this: |
| 144 | |
| 145 | {{{ |
| 146 | #!python |
| 147 | |
| 148 | try: |
| 149 | acc = lib.create_account(pj.AccountConfig("pjsip.org", "username", "password"), True) |
| 150 | |
| 151 | except pj.Error, e: |
| 152 | print "Error creating account:", e |
| 153 | }}} |
| 154 | |
| 155 | |
| 156 | ==== Getting Events from Account ==== |
| 157 | |
| 158 | [http://www.pjsip.org/python/pjsua.htm#Account Account] object emits events such as incoming call and registration state. |
| 159 | |
| 160 | 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: |
| 161 | |
| 162 | {{{ |
| 163 | #!python |
| 164 | |
| 165 | class MyAccountCallback(pj.AccountCallback): |
| 166 | def __init__(self, account): |
| 167 | pj.AccountCallback.__init__(self, account) |
| 168 | |
| 169 | def on_reg_state(self): |
| 170 | print "Account", self.account.info().uri, |
| 171 | print "registration status is", self.account.info().reg_reason |
| 172 | |
| 173 | def on_incoming_call(self, call): |
| 174 | print "Incoming call from", call.info().remote_uri |
| 175 | call.answer(200) |
| 176 | }}} |
| 177 | |
| 178 | (Note: we've touched the [http://www.pjsip.org/python/pjsua.htm#Call Call] object a little bit above, that will be explained later). |
| 179 | |
| 180 | Then install the callback to [http://www.pjsip.org/python/pjsua.htm#Account Account] object: |
| 181 | |
| 182 | {{{ |
| 183 | #!python |
| 184 | |
| 185 | acc_cb = MyAccountCallback(acc) |
| 186 | acc.set_callback(acc_cb) |
| 187 | }}} |
| 188 | |
| 189 | |
| 190 | ==== Account Sample Application ==== |
| 191 | |
| 192 | For a complete account sample application (including registration), please see source:pjproject/trunk/pjsip-apps/src/python/samples/registration.py |
| 193 | |
| 194 | |
| 195 | === Calls === |
| 196 | |
| 197 | ==== Creating Calls ==== |
| 198 | |
| 199 | Incoming call events are reported via [http://www.pjsip.org/python/pjsua.htm#AccountCallback AccountCallback]'s {{{on_incoming_call()}}} callback as shown above. |
| 200 | |
| 201 | To make outgoing call: |
| 202 | |
| 203 | {{{ |
| 204 | #!python |
| 205 | |
| 206 | call = acc.make_call("sip:buddy@pjsip.org") |
| 207 | }}} |
| 208 | |
| 209 | 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). |
| 210 | |
| 211 | ==== Getting Events from Call ==== |
| 212 | |
| 213 | 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: |
| 214 | |
| 215 | {{{ |
| 216 | #!python |
| 217 | |
| 218 | class MyCallCallback(pj.CallCallback): |
| 219 | def __init__(self, call): |
| 220 | pj.CallCallback.__init__(self, call) |
| 221 | |
| 222 | def on_state(self): |
| 223 | print "Call with", self.call.info().remote_uri, |
| 224 | print "is", self.call.info().state_text |
| 225 | |
| 226 | def on_media_state(self): |
| 227 | if self.call.info().media_state == pj.MediaState.ACTIVE: |
| 228 | # Connect the call to sound device |
| 229 | call_slot = self.call.info().conf_slot |
| 230 | pj.Lib.instance().conf_connect(call_slot, 0) |
| 231 | pj.Lib.instance().conf_connect(0, call_slot) |
| 232 | print "Media is now active" |
| 233 | else: |
| 234 | print "Media is inactive" |
| 235 | |
| 236 | }}} |
| 237 | |
| 238 | Then install your callback to the call object: |
| 239 | |
| 240 | {{{ |
| 241 | #!python |
| 242 | |
| 243 | call_cb = MyCallCallback(call) |
| 244 | call.set_callback(call_cb) |
| 245 | }}} |
| 246 | |
| 247 | |
| 248 | ==== Call Sample Application ==== |
| 249 | |
| 250 | For a complete call sample application, please see source:pjproject/trunk/pjsip-apps/src/python/samples/call.py |
| 251 | |