blob: 7aa7d3e9aed7e724032933037dd04983d35e292f [file] [log] [blame]
Benny Prijonodc308702006-12-09 00:39:42 +00001import py_pjsua
2import sys
3import thread
4
5#
6# Configurations
7#
Benny Prijonoed7a5a72007-01-29 18:36:38 +00008THIS_FILE = "pjsua_app.py"
Benny Prijonodc308702006-12-09 00:39:42 +00009C_QUIT = 0
Benny Prijonoed7a5a72007-01-29 18:36:38 +000010C_LOG_LEVEL = 4
Benny Prijonodc308702006-12-09 00:39:42 +000011
Benny Prijonoed7a5a72007-01-29 18:36:38 +000012# STUN config.
13# Set C_STUN_SRV to the address of the STUN server to enable STUN
14#
Benny Prijonodc308702006-12-09 00:39:42 +000015C_STUN_SRV = ""
Benny Prijonoed7a5a72007-01-29 18:36:38 +000016C_SIP_PORT = 5060
Benny Prijonodc308702006-12-09 00:39:42 +000017C_STUN_PORT = 3478
18
Benny Prijonodc308702006-12-09 00:39:42 +000019
Benny Prijonoed7a5a72007-01-29 18:36:38 +000020# Globals
21#
22g_acc_id = py_pjsua.PJSUA_INVALID_ID
23g_current_call = py_pjsua.PJSUA_INVALID_ID
24
25
26# Utility to get call info
27#
28def call_name(call_id):
29 ci = py_pjsua.call_get_info(call_id)
30 return "[Call " + `call_id` + " " + ci.remote_info + "]"
31
32# Handler when invite state has changed.
33#
34def on_call_state(call_id, e):
35 global g_current_call
36 ci = py_pjsua.call_get_info(call_id)
37 write_log(3, call_name(call_id) + " state = " + `ci.state_text`)
38 if ci.state == 6:
39 g_current_call = py_pjsua.PJSUA_INVALID_ID
40
41# Handler for incoming call
42#
43def on_incoming_call(acc_id, call_id, rdata):
44 global g_current_call
45 if g_current_call != py_pjsua.PJSUA_INVALID_ID:
46 py_pjsua.call_answer(call_id, 486, "", None)
47 return
48 g_current_call = call_id
49 ci = py_pjsua.call_get_info(call_id)
50 write_log(3, "Incoming call: " + call_name(call_id))
51 py_pjsua.call_answer(call_id, 200, "", None)
52
53
54# Handler when media state has changed (e.g. established or terminated)
55#
56def on_call_media_state(call_id):
57 ci = py_pjsua.call_get_info(call_id)
58 if ci.media_status == 1:
59 py_pjsua.conf_connect(ci.conf_slot, 0)
60 py_pjsua.conf_connect(0, ci.conf_slot)
61 write_log(3, call_name(call_id) + ": media is active")
62 else:
63 write_log(3, call_name(call_id) + ": media is inactive")
64
65
66# Handler when account registration state has changed
67#
68def on_reg_state(acc_id):
69 acc_info = py_pjsua.acc_get_info(acc_id)
70 if acc_info.status != 0 and acc_info.status != 200:
71 write_log(3, "Account (un)registration failed: rc=" + `acc_info.status` + " " + acc_info.status_text)
72 else:
73 write_log(3, "Account successfully (un)registered")
74
75
Fahrise314b882007-02-02 10:52:04 +000076def on_buddy_state(buddy_id):
77 write_log(3, "On Buddy state called")
78 buddy_info = py_pjsua.buddy_get_info(buddy_id)
79 if buddy_info.status != 0 and buddy_info.status != 200:
80 write_log(3, "Status of " + `buddy_info.uri` + " is " + `buddy_info.status_text`)
81 else:
82 write_log(3, "Status : " + `buddy_info.status`)
83
84def on_pager(call_id, strfrom, strto, contact, mime_type, text):
85 write_log(3, "MESSAGE from " + `strfrom` + " : " + `text`)
86
87def on_pager_status(call_id, strto, body, user_data, status, reason):
88 write_log(3, "MESSAGE to " + `strto` + " status " + `status` + " reason " + `reason`)
89
Benny Prijonoed7a5a72007-01-29 18:36:38 +000090# Utility: display PJ error and exit
91#
Benny Prijonodc308702006-12-09 00:39:42 +000092def err_exit(title, rc):
Benny Prijonoed7a5a72007-01-29 18:36:38 +000093 py_pjsua.perror(THIS_FILE, title, rc)
Benny Prijonodc308702006-12-09 00:39:42 +000094 exit(1)
95
Benny Prijonoed7a5a72007-01-29 18:36:38 +000096
97# Logging function (also callback, called by pjsua-lib)
98#
Benny Prijonodc308702006-12-09 00:39:42 +000099def log_cb(level, str, len):
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000100 if level <= C_LOG_LEVEL:
Benny Prijonodc308702006-12-09 00:39:42 +0000101 print str,
102
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000103def write_log(level, str):
104 log_cb(level, str + "\n", 0)
105
106
107#
108# Initialize pjsua.
109#
Benny Prijonodc308702006-12-09 00:39:42 +0000110def app_init():
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000111 global g_acc_id
Benny Prijonodc308702006-12-09 00:39:42 +0000112
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000113 # Create pjsua before anything else
114 status = py_pjsua.create()
115 if status != 0:
116 err_exit("pjsua create() error", status)
Benny Prijonodc308702006-12-09 00:39:42 +0000117
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000118 # Create and initialize logging config
119 log_cfg = py_pjsua.logging_config_default()
120 log_cfg.level = C_LOG_LEVEL
121 log_cfg.cb = log_cb
Benny Prijonodc308702006-12-09 00:39:42 +0000122
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000123 # Create and initialize pjsua config
124 # Note: for this Python module, thread_cnt must be 0 since Python
125 # doesn't like to be called from alien thread (pjsua's thread
126 # in this case)
127 ua_cfg = py_pjsua.config_default()
128 ua_cfg.thread_cnt = 0
129 ua_cfg.user_agent = "PJSUA/Python 0.1"
130 ua_cfg.cb.on_incoming_call = on_incoming_call
131 ua_cfg.cb.on_call_media_state = on_call_media_state
132 ua_cfg.cb.on_reg_state = on_reg_state
133 ua_cfg.cb.on_call_state = on_call_state
Fahrise314b882007-02-02 10:52:04 +0000134 ua_cfg.cb.on_buddy_state = on_buddy_state
135 ua_cfg.cb.on_pager = on_pager
136 ua_cfg.cb.on_pager_status = on_pager_status
137
Benny Prijonodc308702006-12-09 00:39:42 +0000138
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000139 # Create and initialize media config
140 med_cfg = py_pjsua.media_config_default()
141 med_cfg.ec_tail_len = 0
Benny Prijonodc308702006-12-09 00:39:42 +0000142
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000143 #
144 # Initialize pjsua!!
145 #
146 status = py_pjsua.init(ua_cfg, log_cfg, med_cfg)
147 if status != 0:
148 err_exit("pjsua init() error", status)
Benny Prijonodc308702006-12-09 00:39:42 +0000149
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000150 # Configure STUN config
151 stun_cfg = py_pjsua.stun_config_default()
152 stun_cfg.stun_srv1 = C_STUN_SRV
153 stun_cfg.stun_srv2 = C_STUN_SRV
154 stun_cfg.stun_port1 = C_STUN_PORT
155 stun_cfg.stun_port2 = C_STUN_PORT
Benny Prijonodc308702006-12-09 00:39:42 +0000156
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000157 # Configure UDP transport config
158 transport_cfg = py_pjsua.transport_config_default()
159 transport_cfg.port = C_SIP_PORT
160 transport_cfg.stun_config = stun_cfg
161 if C_STUN_SRV != "":
162 transport_cfg.use_stun = 1
163
164 # Create UDP transport
165 status, transport_id = py_pjsua.transport_create(1, transport_cfg)
166 if status != 0:
167 py_pjsua.destroy()
168 err_exit("Error creating UDP transport", status)
169
170 # Create initial default account
171 status, acc_id = py_pjsua.acc_add_local(transport_id, 1)
172 if status != 0:
173 py_pjsua.destroy()
174 err_exit("Error creating account", status)
175
176 g_acc_id = acc_id
177
178# Add SIP account interractively
179#
180def add_account():
181 global g_acc_id
182
183 acc_domain = ""
184 acc_username = ""
185 acc_passwd =""
186 confirm = ""
187
188 # Input account configs
189 print "Your SIP domain (e.g. myprovider.com): ",
190 acc_domain = sys.stdin.readline()
191 if acc_domain == "\n":
192 return
193 acc_domain = acc_domain.replace("\n", "")
194
195 print "Your username (e.g. alice): ",
196 acc_username = sys.stdin.readline()
197 if acc_username == "\n":
198 return
199 acc_username = acc_username.replace("\n", "")
200
201 print "Your password (e.g. secret): ",
202 acc_passwd = sys.stdin.readline()
203 if acc_passwd == "\n":
204 return
205 acc_passwd = acc_passwd.replace("\n", "")
206
207 # Configure account configuration
208 acc_cfg = py_pjsua.acc_config_default()
209 acc_cfg.id = "sip:" + acc_username + "@" + acc_domain
210 acc_cfg.reg_uri = "sip:" + acc_domain
211 acc_cfg.cred_count = 1
212 acc_cfg.cred_info[0].realm = acc_domain
213 acc_cfg.cred_info[0].scheme = "digest"
214 acc_cfg.cred_info[0].username = acc_username
215 acc_cfg.cred_info[0].data_type = 0
216 acc_cfg.cred_info[0].data = acc_passwd
217
218 # Add new SIP account
219 status, acc_id = py_pjsua.acc_add(acc_cfg, 1)
220 if status != 0:
221 py_pjsua.perror(THIS_FILE, "Error adding SIP account", status)
222 else:
223 g_acc_id = acc_id
224 write_log(3, "Account " + acc_cfg.id + " added")
Benny Prijonodc308702006-12-09 00:39:42 +0000225
226
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000227#
228# Worker thread function.
229# Python doesn't like it when it's called from an alien thread
230# (pjsua's worker thread, in this case), so for Python we must
231# disable worker thread in pjsua and poll pjsua from Python instead.
232#
Benny Prijonodc308702006-12-09 00:39:42 +0000233def worker_thread_main(arg):
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000234 global C_QUIT
235 thread_desc = 0;
236 status = py_pjsua.thread_register("python worker", thread_desc)
237 if status != 0:
238 py_pjsua.perror(THIS_FILE, "Error registering thread", status)
239 else:
240 while C_QUIT == 0:
241 py_pjsua.handle_events(50)
242 print "Worker thread quitting.."
243 C_QUIT = 2
244
Benny Prijonodc308702006-12-09 00:39:42 +0000245
246# Start pjsua
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000247#
Benny Prijonodc308702006-12-09 00:39:42 +0000248def app_start():
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000249 # Done with initialization, start pjsua!!
250 #
251 status = py_pjsua.start()
252 if status != 0:
253 py_pjsua.destroy()
254 err_exit("Error starting pjsua!", status)
Benny Prijonodc308702006-12-09 00:39:42 +0000255
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000256 # Start worker thread
257 thr = thread.start_new(worker_thread_main, (0,))
Benny Prijonodc308702006-12-09 00:39:42 +0000258
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000259 print "PJSUA Started!!"
Benny Prijonodc308702006-12-09 00:39:42 +0000260
261
262# Print application menu
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000263#
Benny Prijonodc308702006-12-09 00:39:42 +0000264def print_menu():
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000265 print """
266Menu:
267 q Quit application
268 +a Add account
269 +b Add buddy
270 m Make call
271 h Hangup current call (if any)
272 i Send instant message
273 """
274 print "Choice: ",
Benny Prijonodc308702006-12-09 00:39:42 +0000275
Benny Prijonodc308702006-12-09 00:39:42 +0000276# Menu
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000277#
Benny Prijonodc308702006-12-09 00:39:42 +0000278def app_menu():
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000279 global g_acc_id
280 global g_current_call
281
282 quit = 0
283 while quit == 0:
284 print_menu()
285 choice = sys.stdin.readline()
286
287 if choice[0] == "q":
288 quit = 1
289
290 elif choice[0] == "i":
291 # Sending IM
292 print "Send IM to SIP URL: ",
293 url = sys.stdin.readline()
294 if url == "\n":
295 continue
296
297 # Send typing indication
298 py_pjsua.im_typing(g_acc_id, url, 1, None)
299
300 print "The content: ",
301 message = sys.stdin.readline()
302 if message == "\n":
303 py_pjsua.im_typing(g_acc_id, url, 0, None)
304 continue
305
306 # Send the IM!
307 py_pjsua.im_send(g_acc_id, url, "", message, None, 0)
308
309 elif choice[0] == "m":
310 # Make call
311 print "Using account ", g_acc_id
312 print "Make call to SIP URL: ",
313 url = sys.stdin.readline()
314 url = url.replace("\n", "")
315 if url == "":
316 continue
317
318 # Initiate the call!
319 status, call_id = py_pjsua.call_make_call(g_acc_id, url, 0, 0, None)
Benny Prijonodc308702006-12-09 00:39:42 +0000320
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000321 if status != 0:
322 py_pjsua.perror(THIS_FILE, "Error making call", status)
323 else:
324 g_current_call = call_id
325
326 elif choice[0] == "+" and choice[1] == "b":
327 # Add new buddy
328 bc = py_pjsua.Buddy_Config()
329 print "Buddy URL: ",
330 bc.uri = sys.stdin.readline()
331 if bc.uri == "\n":
332 continue
333
334 bc.subscribe = 1
335 status, buddy_id = py_pjsua.buddy_add(bc)
336 if status != 0:
337 py_pjsua.perror(THIS_FILE, "Error adding buddy", status)
338
339 elif choice[0] == "+" and choice[1] == "a":
340 # Add account
341 add_account()
342
343 elif choice[0] == "h":
344 if g_current_call != py_pjsua.PJSUA_INVALID_ID:
345 py_pjsua.call_hangup(g_current_call, 603, "", None)
346 else:
347 print "No current call"
Benny Prijonodc308702006-12-09 00:39:42 +0000348
349
350#
351# main
352#
353app_init()
354app_start()
355app_menu()
356
357#
358# Done, quitting..
359#
360print "PJSUA shutting down.."
361C_QUIT = 1
Benny Prijonoed7a5a72007-01-29 18:36:38 +0000362# Give the worker thread chance to quit itself
363while C_QUIT != 2:
364 py_pjsua.handle_events(50)
365
366print "PJSUA destroying.."
Benny Prijonodc308702006-12-09 00:39:42 +0000367py_pjsua.destroy()
368