23 | | |
24 | | == Getting the Module == #getting |
25 | | |
26 | | The Python module source codes along with some samples are included in PJSIP distribution, in [source:pjproject/trunk/pjsip-apps/src/python pjproject/pjsip-apps/src/python] directory. |
27 | | |
28 | | |
29 | | == Building The Modules == #build |
30 | | |
31 | | Using Microsoft Visual Studio projects: |
32 | | * Open '''pjsip-apps.dsw''' from {{{pjsip-apps\build}}} directory. |
33 | | * Select '''python_pjsua''' project as the active project. |
34 | | * Build the project |
35 | | * The {{{_pjsua.pyd}}} Python module will be placed in {{{pjsip-apps\lib}}} directory. |
36 | | * 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. |
37 | | |
38 | | Using Python build script: |
39 | | * Go to {{{pjsip-apps/src/python}}} directory. |
40 | | * Run '''{{{'python ./setup.py build'}}}''' |
41 | | * The Python module will be placed in {{{build}}} directory inside current directory. |
42 | | * Alternatively run '''{{{'python ./setup.py install'}}}''' to install both '''_pjsua''' and '''pjsua''' modules to Python's site_packages directory. |
43 | | |
44 | | [[BR]] |
45 | | |
46 | | |
47 | | == Developing Python SIP Application == #develop |
48 | | |
49 | | === Concepts === #concepts |
50 | | |
51 | | ==== Asynchronous Operations ==== |
52 | | |
53 | | If you have developed applications with PJSIP you'll know about this already, but this concept probably needs to be explained a little bit here to new PJSIP users. |
54 | | |
55 | | In PJSIP, all operations that involve sending and receiving SIP messages are asynchronous, meaning that the function that invokes the operation will complete immediately, and you will be given the completion status as callbacks. Take a look for example the {{{make_call()}}} method of the [http://www.pjsip.org/python/pjsua.htm#Account Account] class. This function is used to initiate outgoing call to a destination. When this function returns successfully, it does not mean that the call has been established, but rather that the call has been '''initiated''' successfully. You will be given the report of the call completion (such as ''Ringing'' or ''Connected''/''Confirmed''' events) in the {{{on_state()}}} callback of [http://www.pjsip.org/python/pjsua.htm#CallCallback CallCallback] class. |
56 | | |
57 | | |
58 | | ==== Basic Usage Pattern ==== |
59 | | |
60 | | Ah, talking about callbacks. |
61 | | |
62 | | |
63 | | |
64 | | ==== Error Handling ==== |
65 | | |
66 | | By convention, we use exceptions as means to report error, as this would make the program flows more naturally. Operations which yield error will raise [http://www.pjsip.org/python/pjsua.htm#Error pjsua.Error] exception. Here is a sample: |
67 | | |
68 | | {{{ |
69 | | #!python |
70 | | import pjsua |
71 | | |
72 | | try: |
73 | | call = acc.make_call('sip:buddy@example.org') |
74 | | except pjsua.Error, err: |
75 | | print 'Exception has occured:', err |
76 | | except: |
77 | | print 'Ouch..' |
78 | | }}} |
79 | | |
80 | | The sample above will print the full error information to stdout. If you prefer to display the error in more structured manner, the [http://www.pjsip.org/python/pjsua.htm#Error pjsua.Error] class has several members to explain the error, such as the object name that raised the error, the operation name, and the error message itself. |
81 | | |
82 | | |
83 | | |
84 | | |
85 | | == Lib Class == |
86 | | |
87 | | 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]). |
88 | | |
89 | | [[BR]] |
90 | | |
91 | | ==== Initializing the Library ==== |
92 | | |
93 | | Instantiate the library: |
94 | | |
95 | | {{{ |
96 | | #!python |
97 | | |
98 | | import pjsua as pj |
99 | | |
100 | | lib = pj.Lib() |
101 | | |
102 | | }}} |
103 | | |
104 | | then initialize and start the library. |
105 | | |
106 | | {{{ |
107 | | #!python |
108 | | |
109 | | try: |
110 | | lib.init() |
111 | | lib.start() |
112 | | |
113 | | except pj.Error, e: |
114 | | print "Error initializing library:", e |
115 | | }}} |
116 | | |
117 | | 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. |
118 | | |
119 | | [[BR]] |
120 | | |
121 | | == Transport == |
122 | | |
123 | | 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: |
124 | | |
125 | | {{{ |
126 | | #!python |
127 | | |
128 | | try: |
129 | | udp = lib.create_transport(pj.TransportType.UDP) |
130 | | |
131 | | except pj.Error, e: |
132 | | print "Error creating transport:", e |
133 | | }}} |
134 | | |
135 | | [[BR]] |
136 | | |
137 | | == Accounts == |
138 | | |
139 | | 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. |
140 | | |
141 | | There are two types of accounts in pjsua: |
142 | | * real account: this is an account that can register to a SIP server |
143 | | * 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}}}"). |
144 | | |
145 | | There can be more than one accounts in an application. |
146 | | |
147 | | [[BR]] |
148 | | |
149 | | ==== Creating Accounts ==== |
150 | | |
151 | | To create transport account: |
152 | | |
153 | | {{{ |
154 | | #!python |
155 | | |
156 | | try: |
157 | | acc = lib.create_account_for_transport(udp) |
158 | | |
159 | | except pj.Error, e: |
160 | | print "Error creating UDP local account:", e |
161 | | }}} |
162 | | |
163 | | To create a real account account, first you must configure an [http://www.pjsip.org/python/pjsua.htm#AccountConfig AccountConfig], then create the account: |
164 | | |
165 | | {{{ |
166 | | #!python |
167 | | |
168 | | try: |
169 | | acc_cfg = pj.AccountConfig() |
170 | | acc_cfg.id = "sip:user@pjsip.org" |
171 | | acc_cfg.reg_uri = "sip:pjsip.org" |
172 | | acc_cfg.proxy = ["<sip:pjsip.org;lr>"] |
173 | | acc_cfg.auth_cred = [pj.AuthCred("*", "user", "password")] |
174 | | |
175 | | acc = lib.create_account(acc_cfg, True) |
176 | | |
177 | | except pj.Error, e: |
178 | | print "Error creating account:", e |
179 | | }}} |
180 | | |
181 | | Alternatively, for typical account config like above, we can do like this: |
182 | | |
183 | | {{{ |
184 | | #!python |
185 | | |
186 | | try: |
187 | | acc = lib.create_account(pj.AccountConfig("pjsip.org", "username", "password"), True) |
188 | | |
189 | | except pj.Error, e: |
190 | | print "Error creating account:", e |
191 | | }}} |
192 | | |
193 | | [[BR]] |
194 | | |
195 | | ==== Getting Events from Account ==== |
196 | | |
197 | | [http://www.pjsip.org/python/pjsua.htm#Account Account] object emits events such as incoming call and registration state. |
198 | | |
199 | | 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: |
200 | | |
201 | | {{{ |
202 | | #!python |
203 | | |
204 | | class MyAccountCallback(pj.AccountCallback): |
205 | | def __init__(self, account): |
206 | | pj.AccountCallback.__init__(self, account) |
207 | | |
208 | | def on_reg_state(self): |
209 | | print "Account", self.account.info().uri, |
210 | | print "registration status is", self.account.info().reg_reason |
211 | | |
212 | | def on_incoming_call(self, call): |
213 | | print "Incoming call from", call.info().remote_uri |
214 | | call.answer(200) |
215 | | }}} |
216 | | |
217 | | (Note: we've touched the [http://www.pjsip.org/python/pjsua.htm#Call Call] object a little bit above, that will be explained later). |
218 | | |
219 | | Then install the callback to [http://www.pjsip.org/python/pjsua.htm#Account Account] object: |
220 | | |
221 | | {{{ |
222 | | #!python |
223 | | |
224 | | acc_cb = MyAccountCallback(acc) |
225 | | acc.set_callback(acc_cb) |
226 | | }}} |
227 | | |
228 | | [[BR]] |
229 | | |
230 | | ==== Account Sample Application ==== |
231 | | |
232 | | For a complete account sample application (including registration), please see source:pjproject/trunk/pjsip-apps/src/python/samples/registration.py |
233 | | |
234 | | |
235 | | [[BR]] |
236 | | |
237 | | == Calls == |
238 | | |
239 | | ==== Creating Calls ==== |
240 | | |
241 | | Incoming call events are reported via [http://www.pjsip.org/python/pjsua.htm#AccountCallback AccountCallback]'s {{{on_incoming_call()}}} callback as shown above. |
242 | | |
243 | | To make outgoing call: |
244 | | |
245 | | {{{ |
246 | | #!python |
247 | | |
248 | | try: |
249 | | call = acc.make_call("sip:buddy@pjsip.org") |
250 | | |
251 | | except pj.Error, e: |
252 | | print "Error in making call:", e |
253 | | }}} |
254 | | |
255 | | 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). |
256 | | |
257 | | [[BR]] |
258 | | |
259 | | ==== Getting Events from Call ==== |
260 | | |
261 | | 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: |
262 | | |
263 | | {{{ |
264 | | #!python |
265 | | |
266 | | class MyCallCallback(pj.CallCallback): |
267 | | def __init__(self, call): |
268 | | pj.CallCallback.__init__(self, call) |
269 | | |
270 | | def on_state(self): |
271 | | print "Call with", self.call.info().remote_uri, |
272 | | print "is", self.call.info().state_text |
273 | | |
274 | | def on_media_state(self): |
275 | | if self.call.info().media_state == pj.MediaState.ACTIVE: |
276 | | # Connect the call to sound device |
277 | | |
278 | | call_slot = self.call.info().conf_slot |
279 | | pj.Lib.instance().conf_connect(call_slot, 0) |
280 | | pj.Lib.instance().conf_connect(0, call_slot) |
281 | | print "Media is now active" |
282 | | else: |
283 | | print "Media is inactive" |
284 | | |
285 | | }}} |
286 | | |
287 | | Then install your callback to the call object: |
288 | | |
289 | | {{{ |
290 | | #!python |
291 | | |
292 | | call_cb = MyCallCallback(call) |
293 | | call.set_callback(call_cb) |
294 | | }}} |
295 | | |
296 | | [[BR]] |
297 | | |
298 | | ==== Call Sample Application ==== |
299 | | |
300 | | For a complete call sample application, please see source:pjproject/trunk/pjsip-apps/src/python/samples/call.py |
301 | | |
302 | | |
303 | | [[BR]] |
304 | | |
305 | | == Presence and Instant Messaging == |
306 | | |
307 | | (The doc is TBD) |
308 | | |
309 | | 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. |
310 | | |
311 | | 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. |
312 | | |
313 | | For a complete presence and instant messaging sample application, please see source:pjproject/trunk/pjsip-apps/src/python/samples/presence.py |
314 | | |
315 | | |
316 | | [[BR]] |
317 | | |
318 | | == Working with Media == |
319 | | |
320 | | The [http://www.pjsip.org/python/pjsua.htm#Lib Lib] class provides API to manage media, such as: |
321 | | * create WAV file player or recorder |
322 | | * manage conference bridge connections |
323 | | * manage codecs |
324 | | * etc. |
325 | | |
326 | | |
327 | | |
328 | | [[BR]] |
329 | | |
330 | | = Reference Documentation = |
331 | | |
332 | | Please see [http://www.pjsip.org/python/pjsua.htm pjsua] Python module documentation for reference. |
333 | | |