blob: 093b96ea50522a487548aa57f740d11038df5b27 [file] [log] [blame]
Benny Prijonoaa286042007-02-03 17:23:22 +00001# $Id$
2#
3# Sample and simple Python script to make and receive calls, and do
4# presence and instant messaging/IM using PJSUA-API binding for Python.
5#
6# Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
7#
Benny Prijonodc308702006-12-09 00:39:42 +00008import py_pjsua
9import sys
10import thread
11
12#
13# Configurations
14#
Benny Prijonoed7a5a72007-01-29 18:36:38 +000015THIS_FILE = "pjsua_app.py"
Benny Prijonodc308702006-12-09 00:39:42 +000016C_QUIT = 0
Benny Prijonoed7a5a72007-01-29 18:36:38 +000017C_LOG_LEVEL = 4
Benny Prijonodc308702006-12-09 00:39:42 +000018
Benny Prijonoed7a5a72007-01-29 18:36:38 +000019# STUN config.
Benny Prijono1f63cc42007-09-10 16:54:22 +000020# Set C_STUN_HOST to the address:port of the STUN server to enable STUN
Benny Prijonoed7a5a72007-01-29 18:36:38 +000021#
Benny Prijonod7ea6052007-09-17 15:44:47 +000022C_STUN_HOST = ""
23#C_STUN_HOST = "192.168.0.2"
Benny Prijono1f63cc42007-09-10 16:54:22 +000024#C_STUN_HOST = "stun.iptel.org:3478"
25
26# SIP port
Benny Prijonoed7a5a72007-01-29 18:36:38 +000027C_SIP_PORT = 5060
Benny Prijonodc308702006-12-09 00:39:42 +000028
Benny Prijonodc308702006-12-09 00:39:42 +000029
Benny Prijonoed7a5a72007-01-29 18:36:38 +000030# Globals
31#
Fahris89ea3d02007-02-07 08:18:35 +000032g_ua_cfg = None
Benny Prijonoed7a5a72007-01-29 18:36:38 +000033g_acc_id = py_pjsua.PJSUA_INVALID_ID
34g_current_call = py_pjsua.PJSUA_INVALID_ID
Fahris89ea3d02007-02-07 08:18:35 +000035g_wav_files = []
36g_wav_id = 0
37g_wav_port = 0
38g_rec_file = ""
39g_rec_id = 0
40g_rec_port = 0
Benny Prijonoed7a5a72007-01-29 18:36:38 +000041
Benny Prijonoda275f62007-02-18 23:49:14 +000042# Utility: display PJ error and exit
43#
44def err_exit(title, rc):
45 py_pjsua.perror(THIS_FILE, title, rc)
Benny Prijono1f63cc42007-09-10 16:54:22 +000046 py_pjsua.destroy()
Benny Prijonoda275f62007-02-18 23:49:14 +000047 exit(1)
48
49
50# Logging function (also callback, called by pjsua-lib)
51#
52def log_cb(level, str, len):
53 if level <= C_LOG_LEVEL:
54 print str,
55
56def write_log(level, str):
57 log_cb(level, str + "\n", 0)
58
59
Benny Prijonoed7a5a72007-01-29 18:36:38 +000060# Utility to get call info
61#
62def call_name(call_id):
63 ci = py_pjsua.call_get_info(call_id)
64 return "[Call " + `call_id` + " " + ci.remote_info + "]"
65
Benny Prijonoaa286042007-02-03 17:23:22 +000066# Callback when call state has changed.
Benny Prijonoed7a5a72007-01-29 18:36:38 +000067#
68def on_call_state(call_id, e):
69 global g_current_call
70 ci = py_pjsua.call_get_info(call_id)
71 write_log(3, call_name(call_id) + " state = " + `ci.state_text`)
Benny Prijonoaa286042007-02-03 17:23:22 +000072 if ci.state == py_pjsua.PJSIP_INV_STATE_DISCONNECTED:
Benny Prijonoed7a5a72007-01-29 18:36:38 +000073 g_current_call = py_pjsua.PJSUA_INVALID_ID
74
Benny Prijonoaa286042007-02-03 17:23:22 +000075# Callback for incoming call
Benny Prijonoed7a5a72007-01-29 18:36:38 +000076#
77def on_incoming_call(acc_id, call_id, rdata):
78 global g_current_call
Fahris89ea3d02007-02-07 08:18:35 +000079
Benny Prijonoed7a5a72007-01-29 18:36:38 +000080 if g_current_call != py_pjsua.PJSUA_INVALID_ID:
Benny Prijonoaa286042007-02-03 17:23:22 +000081 # There's call in progress - answer Busy
82 py_pjsua.call_answer(call_id, 486, None, None)
Benny Prijonoed7a5a72007-01-29 18:36:38 +000083 return
Fahris89ea3d02007-02-07 08:18:35 +000084
Benny Prijonoed7a5a72007-01-29 18:36:38 +000085 g_current_call = call_id
86 ci = py_pjsua.call_get_info(call_id)
Benny Prijonoaa286042007-02-03 17:23:22 +000087 write_log(3, "*** Incoming call: " + call_name(call_id) + "***")
Fahris89ea3d02007-02-07 08:18:35 +000088 write_log(3, "*** Press a to answer or h to hangup ***")
89
90
Benny Prijonoed7a5a72007-01-29 18:36:38 +000091
Benny Prijonoaa286042007-02-03 17:23:22 +000092# Callback when media state has changed (e.g. established or terminated)
Benny Prijonoed7a5a72007-01-29 18:36:38 +000093#
94def on_call_media_state(call_id):
95 ci = py_pjsua.call_get_info(call_id)
Benny Prijonoaa286042007-02-03 17:23:22 +000096 if ci.media_status == py_pjsua.PJSUA_CALL_MEDIA_ACTIVE:
Benny Prijonoed7a5a72007-01-29 18:36:38 +000097 py_pjsua.conf_connect(ci.conf_slot, 0)
98 py_pjsua.conf_connect(0, ci.conf_slot)
99 write_log(3, call_name(call_id) + ": media is active")
100 else:
101 write_log(3, call_name(call_id) + ": media is inactive")
102
103
Benny Prijonoaa286042007-02-03 17:23:22 +0000104# Callback when account registration state has changed
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000105#
106def on_reg_state(acc_id):
107 acc_info = py_pjsua.acc_get_info(acc_id)
Benny Prijonoda275f62007-02-18 23:49:14 +0000108 if acc_info.has_registration != 0:
109 cmd = "registration"
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000110 else:
Benny Prijonoda275f62007-02-18 23:49:14 +0000111 cmd = "unregistration"
112 if acc_info.status != 0 and acc_info.status != 200:
113 write_log(3, "Account " + cmd + " failed: rc=" + `acc_info.status` + " " + acc_info.status_text)
114 else:
115 write_log(3, "Account " + cmd + " success")
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000116
117
Benny Prijonoaa286042007-02-03 17:23:22 +0000118# Callback when buddy's presence state has changed
119#
Fahrise314b882007-02-02 10:52:04 +0000120def on_buddy_state(buddy_id):
121 write_log(3, "On Buddy state called")
122 buddy_info = py_pjsua.buddy_get_info(buddy_id)
123 if buddy_info.status != 0 and buddy_info.status != 200:
124 write_log(3, "Status of " + `buddy_info.uri` + " is " + `buddy_info.status_text`)
125 else:
126 write_log(3, "Status : " + `buddy_info.status`)
Benny Prijonoaa286042007-02-03 17:23:22 +0000127
128# Callback on incoming pager (MESSAGE)
129#
Fahrise314b882007-02-02 10:52:04 +0000130def on_pager(call_id, strfrom, strto, contact, mime_type, text):
131 write_log(3, "MESSAGE from " + `strfrom` + " : " + `text`)
Benny Prijonoaa286042007-02-03 17:23:22 +0000132
133
134# Callback on the delivery status of outgoing pager (MESSAGE)
135#
Fahrise314b882007-02-02 10:52:04 +0000136def on_pager_status(call_id, strto, body, user_data, status, reason):
137 write_log(3, "MESSAGE to " + `strto` + " status " + `status` + " reason " + `reason`)
138
Benny Prijonoaa286042007-02-03 17:23:22 +0000139
Fahris89ea3d02007-02-07 08:18:35 +0000140# Received typing indication
141#
142def on_typing(call_id, strfrom, to, contact, is_typing):
143 str_t = ""
144 if is_typing:
145 str_t = "is typing.."
146 else:
147 str_t = "has stopped typing"
148 write_log(3, "IM indication: " + strfrom + " " + str_t)
149
Benny Prijonoda275f62007-02-18 23:49:14 +0000150# Received the status of previous call transfer request
Fahris89ea3d02007-02-07 08:18:35 +0000151#
152def on_call_transfer_status(call_id,status_code,status_text,final,p_cont):
153 strfinal = ""
154 if final == 1:
155 strfinal = "[final]"
156
157 write_log(3, "Call " + `call_id` + ": transfer status= " + `status_code` + " " + status_text+ " " + strfinal)
158
159 if status_code/100 == 2:
160 write_log(3, "Call " + `call_id` + " : call transfered successfully, disconnecting call")
161 status = py_pjsua.call_hangup(call_id, 410, None, None)
162 p_cont = 0
163
Benny Prijonoda275f62007-02-18 23:49:14 +0000164# Callback on incoming call transfer request
Fahris89ea3d02007-02-07 08:18:35 +0000165#
166def on_call_transfer_request(call_id, dst, code):
167 write_log(3, "Call transfer request from " + `call_id` + " to " + dst + " with code " + `code`)
168
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000169#
170# Initialize pjsua.
171#
Benny Prijonodc308702006-12-09 00:39:42 +0000172def app_init():
Fahris89ea3d02007-02-07 08:18:35 +0000173 global g_acc_id, g_ua_cfg
Benny Prijonodc308702006-12-09 00:39:42 +0000174
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000175 # Create pjsua before anything else
176 status = py_pjsua.create()
177 if status != 0:
178 err_exit("pjsua create() error", status)
Benny Prijonodc308702006-12-09 00:39:42 +0000179
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000180 # Create and initialize logging config
181 log_cfg = py_pjsua.logging_config_default()
182 log_cfg.level = C_LOG_LEVEL
183 log_cfg.cb = log_cb
Benny Prijonodc308702006-12-09 00:39:42 +0000184
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000185 # Create and initialize pjsua config
186 # Note: for this Python module, thread_cnt must be 0 since Python
187 # doesn't like to be called from alien thread (pjsua's thread
188 # in this case)
189 ua_cfg = py_pjsua.config_default()
190 ua_cfg.thread_cnt = 0
191 ua_cfg.user_agent = "PJSUA/Python 0.1"
192 ua_cfg.cb.on_incoming_call = on_incoming_call
193 ua_cfg.cb.on_call_media_state = on_call_media_state
194 ua_cfg.cb.on_reg_state = on_reg_state
195 ua_cfg.cb.on_call_state = on_call_state
Fahrise314b882007-02-02 10:52:04 +0000196 ua_cfg.cb.on_buddy_state = on_buddy_state
197 ua_cfg.cb.on_pager = on_pager
198 ua_cfg.cb.on_pager_status = on_pager_status
Fahris89ea3d02007-02-07 08:18:35 +0000199 ua_cfg.cb.on_typing = on_typing
200 ua_cfg.cb.on_call_transfer_status = on_call_transfer_status
201 ua_cfg.cb.on_call_transfer_request = on_call_transfer_request
Benny Prijonodc308702006-12-09 00:39:42 +0000202
Benny Prijono1f63cc42007-09-10 16:54:22 +0000203 # Configure STUN setting
204 if C_STUN_HOST != "":
205 ua_cfg.stun_host = C_STUN_HOST;
206
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000207 # Create and initialize media config
208 med_cfg = py_pjsua.media_config_default()
209 med_cfg.ec_tail_len = 0
Benny Prijonodc308702006-12-09 00:39:42 +0000210
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000211 #
212 # Initialize pjsua!!
213 #
214 status = py_pjsua.init(ua_cfg, log_cfg, med_cfg)
215 if status != 0:
216 err_exit("pjsua init() error", status)
Benny Prijonodc308702006-12-09 00:39:42 +0000217
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000218 # Configure UDP transport config
219 transport_cfg = py_pjsua.transport_config_default()
220 transport_cfg.port = C_SIP_PORT
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000221
222 # Create UDP transport
Benny Prijonoaa286042007-02-03 17:23:22 +0000223 status, transport_id = \
224 py_pjsua.transport_create(py_pjsua.PJSIP_TRANSPORT_UDP, transport_cfg)
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000225 if status != 0:
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000226 err_exit("Error creating UDP transport", status)
Benny Prijono1f63cc42007-09-10 16:54:22 +0000227
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000228
229 # Create initial default account
230 status, acc_id = py_pjsua.acc_add_local(transport_id, 1)
231 if status != 0:
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000232 err_exit("Error creating account", status)
233
234 g_acc_id = acc_id
Fahris89ea3d02007-02-07 08:18:35 +0000235 g_ua_cfg = ua_cfg
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000236
237# Add SIP account interractively
238#
239def add_account():
240 global g_acc_id
241
242 acc_domain = ""
243 acc_username = ""
244 acc_passwd =""
245 confirm = ""
246
247 # Input account configs
248 print "Your SIP domain (e.g. myprovider.com): ",
249 acc_domain = sys.stdin.readline()
250 if acc_domain == "\n":
251 return
252 acc_domain = acc_domain.replace("\n", "")
253
254 print "Your username (e.g. alice): ",
255 acc_username = sys.stdin.readline()
256 if acc_username == "\n":
257 return
258 acc_username = acc_username.replace("\n", "")
259
260 print "Your password (e.g. secret): ",
261 acc_passwd = sys.stdin.readline()
262 if acc_passwd == "\n":
263 return
264 acc_passwd = acc_passwd.replace("\n", "")
265
266 # Configure account configuration
267 acc_cfg = py_pjsua.acc_config_default()
268 acc_cfg.id = "sip:" + acc_username + "@" + acc_domain
269 acc_cfg.reg_uri = "sip:" + acc_domain
Benny Prijonod7ea6052007-09-17 15:44:47 +0000270
271 cred_info = py_pjsua.Pjsip_Cred_Info()
272 cred_info.realm = "*"
273 cred_info.scheme = "digest"
274 cred_info.username = acc_username
275 cred_info.data_type = 0
276 cred_info.data = acc_passwd
277
278 acc_cfg.cred_info.append(1)
279 acc_cfg.cred_info[0] = cred_info
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000280
281 # Add new SIP account
282 status, acc_id = py_pjsua.acc_add(acc_cfg, 1)
283 if status != 0:
284 py_pjsua.perror(THIS_FILE, "Error adding SIP account", status)
285 else:
286 g_acc_id = acc_id
287 write_log(3, "Account " + acc_cfg.id + " added")
Benny Prijonodc308702006-12-09 00:39:42 +0000288
Fahris89ea3d02007-02-07 08:18:35 +0000289def add_player():
290 global g_wav_files
291 global g_wav_id
292 global g_wav_port
293
294 file_name = ""
295 status = -1
296 wav_id = 0
297
298 print "Enter the path of the file player(e.g. /tmp/audio.wav): ",
299 file_name = sys.stdin.readline()
300 if file_name == "\n":
301 return
302 file_name = file_name.replace("\n", "")
303 status, wav_id = py_pjsua.player_create(file_name, 0)
304 if status != 0:
305 py_pjsua.perror(THIS_FILE, "Error adding file player ", status)
306 else:
307 g_wav_files.append(file_name)
308 if g_wav_id == 0:
309 g_wav_id = wav_id
310 g_wav_port = py_pjsua.player_get_conf_port(wav_id)
311 write_log(3, "File player " + file_name + " added")
312
313def add_recorder():
314 global g_rec_file
315 global g_rec_id
316 global g_rec_port
317
318 file_name = ""
319 status = -1
320 rec_id = 0
321
322 print "Enter the path of the file recorder(e.g. /tmp/audio.wav): ",
323 file_name = sys.stdin.readline()
324 if file_name == "\n":
325 return
326 file_name = file_name.replace("\n", "")
327 status, rec_id = py_pjsua.recorder_create(file_name, 0, None, 0, 0)
328 if status != 0:
329 py_pjsua.perror(THIS_FILE, "Error adding file recorder ", status)
330 else:
331 g_rec_file = file_name
332 g_rec_id = rec_id
333 g_rec_port = py_pjsua.recorder_get_conf_port(rec_id)
334 write_log(3, "File recorder " + file_name + " added")
Benny Prijonodc308702006-12-09 00:39:42 +0000335
Fahris89ea3d02007-02-07 08:18:35 +0000336def conf_list():
Fahris89ea3d02007-02-07 08:18:35 +0000337 ports = None
Fahris89ea3d02007-02-07 08:18:35 +0000338 print "Conference ports : "
Fahris89ea3d02007-02-07 08:18:35 +0000339 ports = py_pjsua.enum_conf_ports()
340
341 for port in ports:
342 info = None
343 info = py_pjsua.conf_get_port_info(port)
344 txlist = ""
Benny Prijonod7ea6052007-09-17 15:44:47 +0000345 for listener in info.listeners:
346 txlist = txlist + "#" + `listener` + " "
Fahris89ea3d02007-02-07 08:18:35 +0000347
348 print "Port #" + `info.slot_id` + "[" + `(info.clock_rate/1000)` + "KHz/" + `(info.samples_per_frame * 1000 / info.clock_rate)` + "ms] " + info.name + " transmitting to: " + txlist
349
350def connect_port():
351 src_port = 0
352 dst_port = 0
353
354 print "Connect src port # (empty to cancel): "
355 src_port = sys.stdin.readline()
356 if src_port == "\n":
357 return
358 src_port = src_port.replace("\n", "")
359 src_port = int(src_port)
360 print "To dst port # (empty to cancel): "
361 dst_port = sys.stdin.readline()
362 if dst_port == "\n":
363 return
364 dst_port = dst_port.replace("\n", "")
365 dst_port = int(dst_port)
366 status = py_pjsua.conf_connect(src_port, dst_port)
367 if status != 0:
368 py_pjsua.perror(THIS_FILE, "Error connecting port ", status)
369 else:
370 write_log(3, "Port connected from " + `src_port` + " to " + `dst_port`)
371
372def disconnect_port():
373 src_port = 0
374 dst_port = 0
375
376 print "Disconnect src port # (empty to cancel): "
377 src_port = sys.stdin.readline()
378 if src_port == "\n":
379 return
380 src_port = src_port.replace("\n", "")
381 src_port = int(src_port)
382 print "From dst port # (empty to cancel): "
383 dst_port = sys.stdin.readline()
384 if dst_port == "\n":
385 return
386 dst_port = dst_port.replace("\n", "")
387 dst_port = int(dst_port)
388 status = py_pjsua.conf_disconnect(src_port, dst_port)
389 if status != 0:
390 py_pjsua.perror(THIS_FILE, "Error disconnecting port ", status)
391 else:
392 write_log(3, "Port disconnected " + `src_port` + " from " + `dst_port`)
393
394def dump_call_quality():
395 global g_current_call
396
397 buf = ""
398 if g_current_call != -1:
399 buf = py_pjsua.call_dump(g_current_call, 1, 1024, " ")
400 write_log(3, "\n" + buf)
401 else:
402 write_log(3, "No current call")
Benny Prijonoda275f62007-02-18 23:49:14 +0000403
Fahris89ea3d02007-02-07 08:18:35 +0000404def xfer_call():
405 global g_current_call
406
407 if g_current_call == -1:
408
409 write_log(3, "No current call")
410
411 else:
412 call = g_current_call
413 ci = py_pjsua.call_get_info(g_current_call)
414 print "Transfering current call ["+ `g_current_call` + "] " + ci.remote_info
415 print "Enter sip url : "
416 url = sys.stdin.readline()
417 if url == "\n":
418 return
419 url = url.replace("\n", "")
420 if call != g_current_call:
421 print "Call has been disconnected"
422 return
423 msg_data = py_pjsua.msg_data_init()
424 status = py_pjsua.call_xfer(g_current_call, url, msg_data);
425 if status != 0:
426 py_pjsua.perror(THIS_FILE, "Error transfering call ", status)
427 else:
428 write_log(3, "Call transfered to " + url)
429
430def xfer_call_replaces():
431 if g_current_call == -1:
432 write_log(3, "No current call")
433 else:
434 call = g_current_call
435
436 ids = py_pjsua.enum_calls()
437 if len(ids) <= 1:
438 print "There are no other calls"
439 return
440
441 ci = py_pjsua.call_get_info(g_current_call)
442 print "Transfer call [" + `g_current_call` + "] " + ci.remote_info + " to one of the following:"
443 for i in range(0, len(ids)):
444 if ids[i] == call:
445 continue
446 call_info = py_pjsua.call_get_info(ids[i])
447 print `ids[i]` + " " + call_info.remote_info + " [" + call_info.state_text + "]"
448
449 print "Enter call number to be replaced : "
450 buf = sys.stdin.readline()
451 buf = buf.replace("\n","")
452 if buf == "":
453 return
454 dst_call = int(buf)
455
456 if call != g_current_call:
457 print "Call has been disconnected"
458 return
459
460 if dst_call == call:
461 print "Destination call number must not be the same as the call being transfered"
462 return
463
464 if dst_call >= py_pjsua.PJSUA_MAX_CALLS:
465 print "Invalid destination call number"
466 return
467
468 if py_pjsua.call_is_active(dst_call) == 0:
469 print "Invalid destination call number"
470 return
471
472 py_pjsua.call_xfer_replaces(call, dst_call, 0, None)
473
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000474#
475# Worker thread function.
476# Python doesn't like it when it's called from an alien thread
477# (pjsua's worker thread, in this case), so for Python we must
478# disable worker thread in pjsua and poll pjsua from Python instead.
479#
Benny Prijonodc308702006-12-09 00:39:42 +0000480def worker_thread_main(arg):
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000481 global C_QUIT
482 thread_desc = 0;
483 status = py_pjsua.thread_register("python worker", thread_desc)
484 if status != 0:
485 py_pjsua.perror(THIS_FILE, "Error registering thread", status)
486 else:
487 while C_QUIT == 0:
488 py_pjsua.handle_events(50)
489 print "Worker thread quitting.."
490 C_QUIT = 2
491
Benny Prijonodc308702006-12-09 00:39:42 +0000492
493# Start pjsua
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000494#
Benny Prijonodc308702006-12-09 00:39:42 +0000495def app_start():
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000496 # Done with initialization, start pjsua!!
497 #
498 status = py_pjsua.start()
499 if status != 0:
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000500 err_exit("Error starting pjsua!", status)
Benny Prijonodc308702006-12-09 00:39:42 +0000501
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000502 # Start worker thread
503 thr = thread.start_new(worker_thread_main, (0,))
Benny Prijonodc308702006-12-09 00:39:42 +0000504
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000505 print "PJSUA Started!!"
Benny Prijonodc308702006-12-09 00:39:42 +0000506
507
Benny Prijonoda275f62007-02-18 23:49:14 +0000508# Print account and buddy list
509def print_acc_buddy_list():
510 global g_acc_id
511
512 acc_ids = py_pjsua.enum_accs()
513 print "Account list:"
514 for acc_id in acc_ids:
515 acc_info = py_pjsua.acc_get_info(acc_id)
516 if acc_info.has_registration == 0:
517 acc_status = acc_info.status_text
518 else:
519 acc_status = `acc_info.status` + "/" + acc_info.status_text + " (expires=" + `acc_info.expires` + ")"
520
521 if acc_id == g_acc_id:
522 print " *",
523 else:
524 print " ",
525
526 print "[" + `acc_id` + "] " + acc_info.acc_uri + ": " + acc_status
527 print " Presence status: ",
528 if acc_info.online_status != 0:
529 print "Online"
530 else:
531 print "Invisible"
532
533 if py_pjsua.get_buddy_count() > 0:
534 print ""
535 print "Buddy list:"
536 buddy_ids = py_pjsua.enum_buddies()
537 for buddy_id in buddy_ids:
538 bi = py_pjsua.buddy_get_info(buddy_id)
539 print " [" + `buddy_id` + "] " + bi.status_text + " " + bi.uri
540
541
Benny Prijonodc308702006-12-09 00:39:42 +0000542# Print application menu
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000543#
Benny Prijonodc308702006-12-09 00:39:42 +0000544def print_menu():
Benny Prijonoda275f62007-02-18 23:49:14 +0000545 print ""
546 print ">>>"
547 print_acc_buddy_list()
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000548 print """
Fahris89ea3d02007-02-07 08:18:35 +0000549+============================================================================+
550| Call Commands : | Buddy, IM & Presence: | Account: |
551| | | |
552| m Make call | +b Add buddy | +a Add account |
553| a Answer current call | -b Delete buddy | -a Delete accnt |
554| h Hangup current call | | |
555| H Hold call | i Send instant message | rr register |
556| v re-inVite (release Hold) | s Subscribe presence | ru Unregister |
557| # Send DTMF string | u Unsubscribe presence | |
558| dq Dump curr. call quality | t ToGgle Online status | |
559| +--------------------------+------------------+
560| x Xfer call | Media Commands: | Status: |
561| X Xfer with Replaces | | |
562| | cl List ports | d Dump status |
Benny Prijonoda275f62007-02-18 23:49:14 +0000563| | cc Connect port | dd Dump detail |
Fahris89ea3d02007-02-07 08:18:35 +0000564| | cd Disconnect port | |
565| | +p Add file player | |
566|------------------------------+ +r Add file recorder | |
567| q Quit application | | |
Benny Prijonoda275f62007-02-18 23:49:14 +0000568+============================================================================+"""
569 print "You have " + `py_pjsua.call_get_count()` + " active call(s)"
570 print ">>>",
Benny Prijonodc308702006-12-09 00:39:42 +0000571
Benny Prijonodc308702006-12-09 00:39:42 +0000572# Menu
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000573#
Benny Prijonodc308702006-12-09 00:39:42 +0000574def app_menu():
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000575 global g_acc_id
576 global g_current_call
577
578 quit = 0
579 while quit == 0:
580 print_menu()
581 choice = sys.stdin.readline()
582
583 if choice[0] == "q":
584 quit = 1
585
586 elif choice[0] == "i":
587 # Sending IM
588 print "Send IM to SIP URL: ",
589 url = sys.stdin.readline()
590 if url == "\n":
591 continue
592
593 # Send typing indication
594 py_pjsua.im_typing(g_acc_id, url, 1, None)
595
596 print "The content: ",
597 message = sys.stdin.readline()
598 if message == "\n":
599 py_pjsua.im_typing(g_acc_id, url, 0, None)
600 continue
601
602 # Send the IM!
Benny Prijonoaa286042007-02-03 17:23:22 +0000603 py_pjsua.im_send(g_acc_id, url, None, message, None, 0)
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000604
605 elif choice[0] == "m":
606 # Make call
607 print "Using account ", g_acc_id
608 print "Make call to SIP URL: ",
609 url = sys.stdin.readline()
610 url = url.replace("\n", "")
611 if url == "":
612 continue
613
614 # Initiate the call!
615 status, call_id = py_pjsua.call_make_call(g_acc_id, url, 0, 0, None)
Benny Prijonodc308702006-12-09 00:39:42 +0000616
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000617 if status != 0:
618 py_pjsua.perror(THIS_FILE, "Error making call", status)
619 else:
620 g_current_call = call_id
621
622 elif choice[0] == "+" and choice[1] == "b":
623 # Add new buddy
624 bc = py_pjsua.Buddy_Config()
625 print "Buddy URL: ",
626 bc.uri = sys.stdin.readline()
627 if bc.uri == "\n":
628 continue
629
Benny Prijonoda275f62007-02-18 23:49:14 +0000630 bc.uri = bc.uri.replace("\n", "")
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000631 bc.subscribe = 1
632 status, buddy_id = py_pjsua.buddy_add(bc)
633 if status != 0:
634 py_pjsua.perror(THIS_FILE, "Error adding buddy", status)
Fahris89ea3d02007-02-07 08:18:35 +0000635 elif choice[0] == "-" and choice[1] == "b":
636 print "Enter buddy ID to delete : "
637 buf = sys.stdin.readline()
638 buf = buf.replace("\n","")
639 if buf == "":
640 continue
641 i = int(buf)
642 if py_pjsua.buddy_is_valid(i) == 0:
643 print "Invalid buddy id " + `i`
644 else:
645 py_pjsua.buddy_del(i)
646 print "Buddy " + `i` + " deleted"
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000647 elif choice[0] == "+" and choice[1] == "a":
648 # Add account
649 add_account()
Fahris89ea3d02007-02-07 08:18:35 +0000650 elif choice[0] == "-" and choice[1] == "a":
651 print "Enter account ID to delete : "
652 buf = sys.stdin.readline()
653 buf = buf.replace("\n","")
654 if buf == "":
655 continue
656 i = int(buf)
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000657
Fahris89ea3d02007-02-07 08:18:35 +0000658 if py_pjsua.acc_is_valid(i) == 0:
659 print "Invalid account id " + `i`
660 else:
661 py_pjsua.acc_del(i)
662 print "Account " + `i` + " deleted"
663
664 elif choice[0] == "+" and choice[1] == "p":
665 add_player()
666 elif choice[0] == "+" and choice[1] == "r":
667 add_recorder()
668 elif choice[0] == "c" and choice[1] == "l":
669 conf_list()
670 elif choice[0] == "c" and choice[1] == "c":
671 connect_port()
672 elif choice[0] == "c" and choice[1] == "d":
673 disconnect_port()
674 elif choice[0] == "d" and choice[1] == "q":
675 dump_call_quality()
676 elif choice[0] == "x":
677 xfer_call()
678 elif choice[0] == "X":
679 xfer_call_replaces()
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000680 elif choice[0] == "h":
681 if g_current_call != py_pjsua.PJSUA_INVALID_ID:
Benny Prijonoaa286042007-02-03 17:23:22 +0000682 py_pjsua.call_hangup(g_current_call, 603, None, None)
683 else:
684 print "No current call"
Fahris89ea3d02007-02-07 08:18:35 +0000685 elif choice[0] == "H":
Benny Prijonoaa286042007-02-03 17:23:22 +0000686 if g_current_call != py_pjsua.PJSUA_INVALID_ID:
Fahris89ea3d02007-02-07 08:18:35 +0000687 py_pjsua.call_set_hold(g_current_call, None)
688
689 else:
690 print "No current call"
691 elif choice[0] == "v":
692 if g_current_call != py_pjsua.PJSUA_INVALID_ID:
693
694 py_pjsua.call_reinvite(g_current_call, 1, None);
695
696 else:
697 print "No current call"
698 elif choice[0] == "#":
699 if g_current_call == py_pjsua.PJSUA_INVALID_ID:
700 print "No current call"
701 elif py_pjsua.call_has_media(g_current_call) == 0:
702 print "Media is not established yet!"
703 else:
704 call = g_current_call
705 print "DTMF strings to send (0-9*#A-B)"
706 buf = sys.stdin.readline()
707 buf = buf.replace("\n", "")
708 if buf == "":
709 continue
710 if call != g_current_call:
711 print "Call has been disconnected"
712 continue
713 status = py_pjsua.call_dial_dtmf(g_current_call, buf)
714 if status != 0:
715 py_pjsua.perror(THIS_FILE, "Unable to send DTMF", status);
716 else:
717 print "DTMF digits enqueued for transmission"
718 elif choice[0] == "s":
719 print "Subscribe presence of (buddy id) : "
720 buf = sys.stdin.readline()
721 buf = buf.replace("\n","")
722 if buf == "":
723 continue
724 i = int(buf)
725 py_pjsua.buddy_subscribe_pres(i, 1)
726 elif choice[0] == "u":
727 print "Unsubscribe presence of (buddy id) : "
728 buf = sys.stdin.readline()
729 buf = buf.replace("\n","")
730 if buf == "":
731 continue
732 i = int(buf)
733 py_pjsua.buddy_subscribe_pres(i, 0)
734 elif choice[0] == "t":
735 acc_info = py_pjsua.acc_get_info(g_acc_id)
736 if acc_info.online_status == 0:
737 acc_info.online_status = 1
738 else:
739 acc_info.online_status = 0
740 py_pjsua.acc_set_online_status(g_acc_id, acc_info.online_status)
741 st = ""
742 if acc_info.online_status == 0:
743 st = "offline"
744 else:
745 st = "online"
746 print "Setting " + acc_info.acc_uri + " online status to " + st
747 elif choice[0] == "r":
748 if choice[1] == "r":
749 py_pjsua.acc_set_registration(g_acc_id, 1)
750 elif choice[1] == "u":
751 py_pjsua.acc_set_registration(g_acc_id, 0)
752 elif choice[0] == "d":
Benny Prijonoda275f62007-02-18 23:49:14 +0000753 py_pjsua.dump(choice[1] == "d")
Fahris89ea3d02007-02-07 08:18:35 +0000754 elif choice[0] == "a":
755 if g_current_call != py_pjsua.PJSUA_INVALID_ID:
756
Benny Prijonoaa286042007-02-03 17:23:22 +0000757 py_pjsua.call_answer(g_current_call, 200, None, None)
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000758 else:
759 print "No current call"
Benny Prijonodc308702006-12-09 00:39:42 +0000760
761
762#
763# main
764#
765app_init()
766app_start()
767app_menu()
768
769#
770# Done, quitting..
771#
772print "PJSUA shutting down.."
773C_QUIT = 1
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000774# Give the worker thread chance to quit itself
775while C_QUIT != 2:
776 py_pjsua.handle_events(50)
777
778print "PJSUA destroying.."
Benny Prijonodc308702006-12-09 00:39:42 +0000779py_pjsua.destroy()
780