pjsua_app.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. #
  2. # Sample and simple Python script to make and receive calls, and do
  3. # presence and instant messaging/IM using PJSUA-API binding for Python.
  4. #
  5. # Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
  6. #
  7. import py_pjsua
  8. import sys
  9. import thread
  10. #
  11. # Configurations
  12. #
  13. THIS_FILE = "pjsua_app.py"
  14. C_QUIT = 0
  15. C_LOG_LEVEL = 4
  16. # STUN config.
  17. # Set C_STUN_HOST to the address:port of the STUN server to enable STUN
  18. #
  19. C_STUN_HOST = ""
  20. #C_STUN_HOST = "192.168.0.2"
  21. #C_STUN_HOST = "stun.iptel.org:3478"
  22. # SIP port
  23. C_SIP_PORT = 5060
  24. # Globals
  25. #
  26. g_ua_cfg = None
  27. g_acc_id = py_pjsua.PJSUA_INVALID_ID
  28. g_current_call = py_pjsua.PJSUA_INVALID_ID
  29. g_wav_files = []
  30. g_wav_id = 0
  31. g_wav_port = 0
  32. g_rec_file = ""
  33. g_rec_id = 0
  34. g_rec_port = 0
  35. # Utility: display PJ error and exit
  36. #
  37. def err_exit(title, rc):
  38. py_pjsua.perror(THIS_FILE, title, rc)
  39. py_pjsua.destroy()
  40. exit(1)
  41. # Logging function (also callback, called by pjsua-lib)
  42. #
  43. def log_cb(level, str, len):
  44. if level <= C_LOG_LEVEL:
  45. print str,
  46. def write_log(level, str):
  47. log_cb(level, str + "\n", 0)
  48. # Utility to get call info
  49. #
  50. def call_name(call_id):
  51. ci = py_pjsua.call_get_info(call_id)
  52. return "[Call " + `call_id` + " " + ci.remote_info + "]"
  53. # Callback when call state has changed.
  54. #
  55. def on_call_state(call_id, e):
  56. global g_current_call
  57. ci = py_pjsua.call_get_info(call_id)
  58. write_log(3, call_name(call_id) + " state = " + `ci.state_text`)
  59. if ci.state == py_pjsua.PJSIP_INV_STATE_DISCONNECTED:
  60. g_current_call = py_pjsua.PJSUA_INVALID_ID
  61. # Callback for incoming call
  62. #
  63. def on_incoming_call(acc_id, call_id, rdata):
  64. global g_current_call
  65. if g_current_call != py_pjsua.PJSUA_INVALID_ID:
  66. # There's call in progress - answer Busy
  67. py_pjsua.call_answer(call_id, 486, None, None)
  68. return
  69. g_current_call = call_id
  70. ci = py_pjsua.call_get_info(call_id)
  71. write_log(3, "*** Incoming call: " + call_name(call_id) + "***")
  72. write_log(3, "*** Press a to answer or h to hangup ***")
  73. # Callback when media state has changed (e.g. established or terminated)
  74. #
  75. def on_call_media_state(call_id):
  76. ci = py_pjsua.call_get_info(call_id)
  77. if ci.media_status == py_pjsua.PJSUA_CALL_MEDIA_ACTIVE:
  78. py_pjsua.conf_connect(ci.conf_slot, 0)
  79. py_pjsua.conf_connect(0, ci.conf_slot)
  80. write_log(3, call_name(call_id) + ": media is active")
  81. else:
  82. write_log(3, call_name(call_id) + ": media is inactive")
  83. # Callback when account registration state has changed
  84. #
  85. def on_reg_state(acc_id):
  86. acc_info = py_pjsua.acc_get_info(acc_id)
  87. if acc_info.has_registration != 0:
  88. cmd = "registration"
  89. else:
  90. cmd = "unregistration"
  91. if acc_info.status != 0 and acc_info.status != 200:
  92. write_log(3, "Account " + cmd + " failed: rc=" + `acc_info.status` + " " + acc_info.status_text)
  93. else:
  94. write_log(3, "Account " + cmd + " success")
  95. # Callback when buddy's presence state has changed
  96. #
  97. def on_buddy_state(buddy_id):
  98. write_log(3, "On Buddy state called")
  99. buddy_info = py_pjsua.buddy_get_info(buddy_id)
  100. if buddy_info.status != 0 and buddy_info.status != 200:
  101. write_log(3, "Status of " + `buddy_info.uri` + " is " + `buddy_info.status_text`)
  102. else:
  103. write_log(3, "Status : " + `buddy_info.status`)
  104. # Callback on incoming pager (MESSAGE)
  105. #
  106. def on_pager(call_id, strfrom, strto, contact, mime_type, text):
  107. write_log(3, "MESSAGE from " + `strfrom` + " : " + `text`)
  108. # Callback on the delivery status of outgoing pager (MESSAGE)
  109. #
  110. def on_pager_status(call_id, strto, body, user_data, status, reason):
  111. write_log(3, "MESSAGE to " + `strto` + " status " + `status` + " reason " + `reason`)
  112. # Received typing indication
  113. #
  114. def on_typing(call_id, strfrom, to, contact, is_typing):
  115. str_t = ""
  116. if is_typing:
  117. str_t = "is typing.."
  118. else:
  119. str_t = "has stopped typing"
  120. write_log(3, "IM indication: " + strfrom + " " + str_t)
  121. # Received the status of previous call transfer request
  122. #
  123. def on_call_transfer_status(call_id,status_code,status_text,final,p_cont):
  124. strfinal = ""
  125. if final == 1:
  126. strfinal = "[final]"
  127. write_log(3, "Call " + `call_id` + ": transfer status= " + `status_code` + " " + status_text+ " " + strfinal)
  128. if status_code/100 == 2:
  129. write_log(3, "Call " + `call_id` + " : call transferred successfully, disconnecting call")
  130. status = py_pjsua.call_hangup(call_id, 410, None, None)
  131. p_cont = 0
  132. # Callback on incoming call transfer request
  133. #
  134. def on_call_transfer_request(call_id, dst, code):
  135. write_log(3, "Call transfer request from " + `call_id` + " to " + dst + " with code " + `code`)
  136. #
  137. # Initialize pjsua.
  138. #
  139. def app_init():
  140. global g_acc_id, g_ua_cfg
  141. # Create pjsua before anything else
  142. status = py_pjsua.create()
  143. if status != 0:
  144. err_exit("pjsua create() error", status)
  145. # Create and initialize logging config
  146. log_cfg = py_pjsua.logging_config_default()
  147. log_cfg.level = C_LOG_LEVEL
  148. log_cfg.cb = log_cb
  149. # Create and initialize pjsua config
  150. # Note: for this Python module, thread_cnt must be 0 since Python
  151. # doesn't like to be called from alien thread (pjsua's thread
  152. # in this case)
  153. ua_cfg = py_pjsua.config_default()
  154. ua_cfg.thread_cnt = 0
  155. ua_cfg.user_agent = "PJSUA/Python 0.1"
  156. ua_cfg.cb.on_incoming_call = on_incoming_call
  157. ua_cfg.cb.on_call_media_state = on_call_media_state
  158. ua_cfg.cb.on_reg_state = on_reg_state
  159. ua_cfg.cb.on_call_state = on_call_state
  160. ua_cfg.cb.on_buddy_state = on_buddy_state
  161. ua_cfg.cb.on_pager = on_pager
  162. ua_cfg.cb.on_pager_status = on_pager_status
  163. ua_cfg.cb.on_typing = on_typing
  164. ua_cfg.cb.on_call_transfer_status = on_call_transfer_status
  165. ua_cfg.cb.on_call_transfer_request = on_call_transfer_request
  166. # Configure STUN setting
  167. if C_STUN_HOST != "":
  168. ua_cfg.stun_host = C_STUN_HOST;
  169. # Create and initialize media config
  170. med_cfg = py_pjsua.media_config_default()
  171. med_cfg.ec_tail_len = 0
  172. #
  173. # Initialize pjsua!!
  174. #
  175. status = py_pjsua.init(ua_cfg, log_cfg, med_cfg)
  176. if status != 0:
  177. err_exit("pjsua init() error", status)
  178. # Configure UDP transport config
  179. transport_cfg = py_pjsua.transport_config_default()
  180. transport_cfg.port = C_SIP_PORT
  181. # Create UDP transport
  182. status, transport_id = \
  183. py_pjsua.transport_create(py_pjsua.PJSIP_TRANSPORT_UDP, transport_cfg)
  184. if status != 0:
  185. err_exit("Error creating UDP transport", status)
  186. # Create initial default account
  187. status, acc_id = py_pjsua.acc_add_local(transport_id, 1)
  188. if status != 0:
  189. err_exit("Error creating account", status)
  190. g_acc_id = acc_id
  191. g_ua_cfg = ua_cfg
  192. # Add SIP account interractively
  193. #
  194. def add_account():
  195. global g_acc_id
  196. acc_domain = ""
  197. acc_username = ""
  198. acc_passwd =""
  199. confirm = ""
  200. # Input account configs
  201. print "Your SIP domain (e.g. myprovider.com): ",
  202. acc_domain = sys.stdin.readline()
  203. if acc_domain == "\n":
  204. return
  205. acc_domain = acc_domain.replace("\n", "")
  206. print "Your username (e.g. alice): ",
  207. acc_username = sys.stdin.readline()
  208. if acc_username == "\n":
  209. return
  210. acc_username = acc_username.replace("\n", "")
  211. print "Your password (e.g. secret): ",
  212. acc_passwd = sys.stdin.readline()
  213. if acc_passwd == "\n":
  214. return
  215. acc_passwd = acc_passwd.replace("\n", "")
  216. # Configure account configuration
  217. acc_cfg = py_pjsua.acc_config_default()
  218. acc_cfg.id = "sip:" + acc_username + "@" + acc_domain
  219. acc_cfg.reg_uri = "sip:" + acc_domain
  220. cred_info = py_pjsua.Pjsip_Cred_Info()
  221. cred_info.realm = "*"
  222. cred_info.scheme = "digest"
  223. cred_info.username = acc_username
  224. cred_info.data_type = 0
  225. cred_info.data = acc_passwd
  226. acc_cfg.cred_info.append(1)
  227. acc_cfg.cred_info[0] = cred_info
  228. # Add new SIP account
  229. status, acc_id = py_pjsua.acc_add(acc_cfg, 1)
  230. if status != 0:
  231. py_pjsua.perror(THIS_FILE, "Error adding SIP account", status)
  232. else:
  233. g_acc_id = acc_id
  234. write_log(3, "Account " + acc_cfg.id + " added")
  235. def add_player():
  236. global g_wav_files
  237. global g_wav_id
  238. global g_wav_port
  239. file_name = ""
  240. status = -1
  241. wav_id = 0
  242. print "Enter the path of the file player(e.g. /tmp/audio.wav): ",
  243. file_name = sys.stdin.readline()
  244. if file_name == "\n":
  245. return
  246. file_name = file_name.replace("\n", "")
  247. status, wav_id = py_pjsua.player_create(file_name, 0)
  248. if status != 0:
  249. py_pjsua.perror(THIS_FILE, "Error adding file player ", status)
  250. else:
  251. g_wav_files.append(file_name)
  252. if g_wav_id == 0:
  253. g_wav_id = wav_id
  254. g_wav_port = py_pjsua.player_get_conf_port(wav_id)
  255. write_log(3, "File player " + file_name + " added")
  256. def add_recorder():
  257. global g_rec_file
  258. global g_rec_id
  259. global g_rec_port
  260. file_name = ""
  261. status = -1
  262. rec_id = 0
  263. print "Enter the path of the file recorder(e.g. /tmp/audio.wav): ",
  264. file_name = sys.stdin.readline()
  265. if file_name == "\n":
  266. return
  267. file_name = file_name.replace("\n", "")
  268. status, rec_id = py_pjsua.recorder_create(file_name, 0, None, 0, 0)
  269. if status != 0:
  270. py_pjsua.perror(THIS_FILE, "Error adding file recorder ", status)
  271. else:
  272. g_rec_file = file_name
  273. g_rec_id = rec_id
  274. g_rec_port = py_pjsua.recorder_get_conf_port(rec_id)
  275. write_log(3, "File recorder " + file_name + " added")
  276. def conf_list():
  277. ports = None
  278. print "Conference ports : "
  279. ports = py_pjsua.enum_conf_ports()
  280. for port in ports:
  281. info = None
  282. info = py_pjsua.conf_get_port_info(port)
  283. txlist = ""
  284. for listener in info.listeners:
  285. txlist = txlist + "#" + `listener` + " "
  286. print "Port #" + `info.slot_id` + "[" + `(info.clock_rate/1000)` + "KHz/" + `(info.samples_per_frame * 1000 / info.clock_rate)` + "ms] " + info.name + " transmitting to: " + txlist
  287. def connect_port():
  288. src_port = 0
  289. dst_port = 0
  290. print "Connect src port # (empty to cancel): "
  291. src_port = sys.stdin.readline()
  292. if src_port == "\n":
  293. return
  294. src_port = src_port.replace("\n", "")
  295. src_port = int(src_port)
  296. print "To dst port # (empty to cancel): "
  297. dst_port = sys.stdin.readline()
  298. if dst_port == "\n":
  299. return
  300. dst_port = dst_port.replace("\n", "")
  301. dst_port = int(dst_port)
  302. status = py_pjsua.conf_connect(src_port, dst_port)
  303. if status != 0:
  304. py_pjsua.perror(THIS_FILE, "Error connecting port ", status)
  305. else:
  306. write_log(3, "Port connected from " + `src_port` + " to " + `dst_port`)
  307. def disconnect_port():
  308. src_port = 0
  309. dst_port = 0
  310. print "Disconnect src port # (empty to cancel): "
  311. src_port = sys.stdin.readline()
  312. if src_port == "\n":
  313. return
  314. src_port = src_port.replace("\n", "")
  315. src_port = int(src_port)
  316. print "From dst port # (empty to cancel): "
  317. dst_port = sys.stdin.readline()
  318. if dst_port == "\n":
  319. return
  320. dst_port = dst_port.replace("\n", "")
  321. dst_port = int(dst_port)
  322. status = py_pjsua.conf_disconnect(src_port, dst_port)
  323. if status != 0:
  324. py_pjsua.perror(THIS_FILE, "Error disconnecting port ", status)
  325. else:
  326. write_log(3, "Port disconnected " + `src_port` + " from " + `dst_port`)
  327. def dump_call_quality():
  328. global g_current_call
  329. buf = ""
  330. if g_current_call != -1:
  331. buf = py_pjsua.call_dump(g_current_call, 1, 1024, " ")
  332. write_log(3, "\n" + buf)
  333. else:
  334. write_log(3, "No current call")
  335. def xfer_call():
  336. global g_current_call
  337. if g_current_call == -1:
  338. write_log(3, "No current call")
  339. else:
  340. call = g_current_call
  341. ci = py_pjsua.call_get_info(g_current_call)
  342. print "Transferring current call ["+ `g_current_call` + "] " + ci.remote_info
  343. print "Enter sip url : "
  344. url = sys.stdin.readline()
  345. if url == "\n":
  346. return
  347. url = url.replace("\n", "")
  348. if call != g_current_call:
  349. print "Call has been disconnected"
  350. return
  351. msg_data = py_pjsua.msg_data_init()
  352. status = py_pjsua.call_xfer(g_current_call, url, msg_data);
  353. if status != 0:
  354. py_pjsua.perror(THIS_FILE, "Error transferring call ", status)
  355. else:
  356. write_log(3, "Call transferred to " + url)
  357. def xfer_call_replaces():
  358. if g_current_call == -1:
  359. write_log(3, "No current call")
  360. else:
  361. call = g_current_call
  362. ids = py_pjsua.enum_calls()
  363. if len(ids) <= 1:
  364. print "There are no other calls"
  365. return
  366. ci = py_pjsua.call_get_info(g_current_call)
  367. print "Transfer call [" + `g_current_call` + "] " + ci.remote_info + " to one of the following:"
  368. for i in range(0, len(ids)):
  369. if ids[i] == call:
  370. continue
  371. call_info = py_pjsua.call_get_info(ids[i])
  372. print `ids[i]` + " " + call_info.remote_info + " [" + call_info.state_text + "]"
  373. print "Enter call number to be replaced : "
  374. buf = sys.stdin.readline()
  375. buf = buf.replace("\n","")
  376. if buf == "":
  377. return
  378. dst_call = int(buf)
  379. if call != g_current_call:
  380. print "Call has been disconnected"
  381. return
  382. if dst_call == call:
  383. print "Destination call number must not be the same as the call being transferred"
  384. return
  385. if dst_call >= py_pjsua.PJSUA_MAX_CALLS:
  386. print "Invalid destination call number"
  387. return
  388. if py_pjsua.call_is_active(dst_call) == 0:
  389. print "Invalid destination call number"
  390. return
  391. py_pjsua.call_xfer_replaces(call, dst_call, 0, None)
  392. #
  393. # Worker thread function.
  394. # Python doesn't like it when it's called from an alien thread
  395. # (pjsua's worker thread, in this case), so for Python we must
  396. # disable worker thread in pjsua and poll pjsua from Python instead.
  397. #
  398. def worker_thread_main(arg):
  399. global C_QUIT
  400. thread_desc = 0;
  401. status = py_pjsua.thread_register("python worker", thread_desc)
  402. if status != 0:
  403. py_pjsua.perror(THIS_FILE, "Error registering thread", status)
  404. else:
  405. while C_QUIT == 0:
  406. py_pjsua.handle_events(50)
  407. print "Worker thread quitting.."
  408. C_QUIT = 2
  409. # Start pjsua
  410. #
  411. def app_start():
  412. # Done with initialization, start pjsua!!
  413. #
  414. status = py_pjsua.start()
  415. if status != 0:
  416. err_exit("Error starting pjsua!", status)
  417. # Start worker thread
  418. thr = thread.start_new(worker_thread_main, (0,))
  419. print "PJSUA Started!!"
  420. # Print account and buddy list
  421. def print_acc_buddy_list():
  422. global g_acc_id
  423. acc_ids = py_pjsua.enum_accs()
  424. print "Account list:"
  425. for acc_id in acc_ids:
  426. acc_info = py_pjsua.acc_get_info(acc_id)
  427. if acc_info.has_registration == 0:
  428. acc_status = acc_info.status_text
  429. else:
  430. acc_status = `acc_info.status` + "/" + acc_info.status_text + " (expires=" + `acc_info.expires` + ")"
  431. if acc_id == g_acc_id:
  432. print " *",
  433. else:
  434. print " ",
  435. print "[" + `acc_id` + "] " + acc_info.acc_uri + ": " + acc_status
  436. print " Presence status: ",
  437. if acc_info.online_status != 0:
  438. print "Online"
  439. else:
  440. print "Invisible"
  441. if py_pjsua.get_buddy_count() > 0:
  442. print ""
  443. print "Buddy list:"
  444. buddy_ids = py_pjsua.enum_buddies()
  445. for buddy_id in buddy_ids:
  446. bi = py_pjsua.buddy_get_info(buddy_id)
  447. print " [" + `buddy_id` + "] " + bi.status_text + " " + bi.uri
  448. # Print application menu
  449. #
  450. def print_menu():
  451. print ""
  452. print ">>>"
  453. print_acc_buddy_list()
  454. print """
  455. +============================================================================+
  456. | Call Commands : | Buddy, IM & Presence: | Account: |
  457. | | | |
  458. | m Make call | +b Add buddy | +a Add account |
  459. | a Answer current call | -b Delete buddy | -a Delete accnt |
  460. | h Hangup current call | | |
  461. | H Hold call | i Send instant message | rr register |
  462. | v re-inVite (release Hold) | s Subscribe presence | ru Unregister |
  463. | # Send DTMF string | u Unsubscribe presence | |
  464. | dq Dump curr. call quality | t ToGgle Online status | |
  465. | +--------------------------+------------------+
  466. | x Xfer call | Media Commands: | Status: |
  467. | X Xfer with Replaces | | |
  468. | | cl List ports | d Dump status |
  469. | | cc Connect port | dd Dump detail |
  470. | | cd Disconnect port | |
  471. | | +p Add file player | |
  472. |------------------------------+ +r Add file recorder | |
  473. | q Quit application | | |
  474. +============================================================================+"""
  475. print "You have " + `py_pjsua.call_get_count()` + " active call(s)"
  476. print ">>>",
  477. # Menu
  478. #
  479. def app_menu():
  480. global g_acc_id
  481. global g_current_call
  482. quit = 0
  483. while quit == 0:
  484. print_menu()
  485. choice = sys.stdin.readline()
  486. if choice[0] == "q":
  487. quit = 1
  488. elif choice[0] == "i":
  489. # Sending IM
  490. print "Send IM to SIP URL: ",
  491. url = sys.stdin.readline()
  492. if url == "\n":
  493. continue
  494. # Send typing indication
  495. py_pjsua.im_typing(g_acc_id, url, 1, None)
  496. print "The content: ",
  497. message = sys.stdin.readline()
  498. if message == "\n":
  499. py_pjsua.im_typing(g_acc_id, url, 0, None)
  500. continue
  501. # Send the IM!
  502. py_pjsua.im_send(g_acc_id, url, None, message, None, 0)
  503. elif choice[0] == "m":
  504. # Make call
  505. print "Using account ", g_acc_id
  506. print "Make call to SIP URL: ",
  507. url = sys.stdin.readline()
  508. url = url.replace("\n", "")
  509. if url == "":
  510. continue
  511. # Initiate the call!
  512. status, call_id = py_pjsua.call_make_call(g_acc_id, url, 0, 0, None)
  513. if status != 0:
  514. py_pjsua.perror(THIS_FILE, "Error making call", status)
  515. else:
  516. g_current_call = call_id
  517. elif choice[0] == "+" and choice[1] == "b":
  518. # Add new buddy
  519. bc = py_pjsua.Buddy_Config()
  520. print "Buddy URL: ",
  521. bc.uri = sys.stdin.readline()
  522. if bc.uri == "\n":
  523. continue
  524. bc.uri = bc.uri.replace("\n", "")
  525. bc.subscribe = 1
  526. status, buddy_id = py_pjsua.buddy_add(bc)
  527. if status != 0:
  528. py_pjsua.perror(THIS_FILE, "Error adding buddy", status)
  529. elif choice[0] == "-" and choice[1] == "b":
  530. print "Enter buddy ID to delete : "
  531. buf = sys.stdin.readline()
  532. buf = buf.replace("\n","")
  533. if buf == "":
  534. continue
  535. i = int(buf)
  536. if py_pjsua.buddy_is_valid(i) == 0:
  537. print "Invalid buddy id " + `i`
  538. else:
  539. py_pjsua.buddy_del(i)
  540. print "Buddy " + `i` + " deleted"
  541. elif choice[0] == "+" and choice[1] == "a":
  542. # Add account
  543. add_account()
  544. elif choice[0] == "-" and choice[1] == "a":
  545. print "Enter account ID to delete : "
  546. buf = sys.stdin.readline()
  547. buf = buf.replace("\n","")
  548. if buf == "":
  549. continue
  550. i = int(buf)
  551. if py_pjsua.acc_is_valid(i) == 0:
  552. print "Invalid account id " + `i`
  553. else:
  554. py_pjsua.acc_del(i)
  555. print "Account " + `i` + " deleted"
  556. elif choice[0] == "+" and choice[1] == "p":
  557. add_player()
  558. elif choice[0] == "+" and choice[1] == "r":
  559. add_recorder()
  560. elif choice[0] == "c" and choice[1] == "l":
  561. conf_list()
  562. elif choice[0] == "c" and choice[1] == "c":
  563. connect_port()
  564. elif choice[0] == "c" and choice[1] == "d":
  565. disconnect_port()
  566. elif choice[0] == "d" and choice[1] == "q":
  567. dump_call_quality()
  568. elif choice[0] == "x":
  569. xfer_call()
  570. elif choice[0] == "X":
  571. xfer_call_replaces()
  572. elif choice[0] == "h":
  573. if g_current_call != py_pjsua.PJSUA_INVALID_ID:
  574. py_pjsua.call_hangup(g_current_call, 603, None, None)
  575. else:
  576. print "No current call"
  577. elif choice[0] == "H":
  578. if g_current_call != py_pjsua.PJSUA_INVALID_ID:
  579. py_pjsua.call_set_hold(g_current_call, None)
  580. else:
  581. print "No current call"
  582. elif choice[0] == "v":
  583. if g_current_call != py_pjsua.PJSUA_INVALID_ID:
  584. py_pjsua.call_reinvite(g_current_call, 1, None);
  585. else:
  586. print "No current call"
  587. elif choice[0] == "#":
  588. if g_current_call == py_pjsua.PJSUA_INVALID_ID:
  589. print "No current call"
  590. elif py_pjsua.call_has_media(g_current_call) == 0:
  591. print "Media is not established yet!"
  592. else:
  593. call = g_current_call
  594. print "DTMF strings to send (0-9*#A-B)"
  595. buf = sys.stdin.readline()
  596. buf = buf.replace("\n", "")
  597. if buf == "":
  598. continue
  599. if call != g_current_call:
  600. print "Call has been disconnected"
  601. continue
  602. status = py_pjsua.call_dial_dtmf(g_current_call, buf)
  603. if status != 0:
  604. py_pjsua.perror(THIS_FILE, "Unable to send DTMF", status);
  605. else:
  606. print "DTMF digits enqueued for transmission"
  607. elif choice[0] == "s":
  608. print "Subscribe presence of (buddy id) : "
  609. buf = sys.stdin.readline()
  610. buf = buf.replace("\n","")
  611. if buf == "":
  612. continue
  613. i = int(buf)
  614. py_pjsua.buddy_subscribe_pres(i, 1)
  615. elif choice[0] == "u":
  616. print "Unsubscribe presence of (buddy id) : "
  617. buf = sys.stdin.readline()
  618. buf = buf.replace("\n","")
  619. if buf == "":
  620. continue
  621. i = int(buf)
  622. py_pjsua.buddy_subscribe_pres(i, 0)
  623. elif choice[0] == "t":
  624. acc_info = py_pjsua.acc_get_info(g_acc_id)
  625. if acc_info.online_status == 0:
  626. acc_info.online_status = 1
  627. else:
  628. acc_info.online_status = 0
  629. py_pjsua.acc_set_online_status(g_acc_id, acc_info.online_status)
  630. st = ""
  631. if acc_info.online_status == 0:
  632. st = "offline"
  633. else:
  634. st = "online"
  635. print "Setting " + acc_info.acc_uri + " online status to " + st
  636. elif choice[0] == "r":
  637. if choice[1] == "r":
  638. py_pjsua.acc_set_registration(g_acc_id, 1)
  639. elif choice[1] == "u":
  640. py_pjsua.acc_set_registration(g_acc_id, 0)
  641. elif choice[0] == "d":
  642. py_pjsua.dump(choice[1] == "d")
  643. elif choice[0] == "a":
  644. if g_current_call != py_pjsua.PJSUA_INVALID_ID:
  645. py_pjsua.call_answer(g_current_call, 200, None, None)
  646. else:
  647. print "No current call"
  648. #
  649. # main
  650. #
  651. app_init()
  652. app_start()
  653. app_menu()
  654. #
  655. # Done, quitting..
  656. #
  657. print "PJSUA shutting down.."
  658. C_QUIT = 1
  659. # Give the worker thread chance to quit itself
  660. while C_QUIT != 2:
  661. py_pjsua.handle_events(50)
  662. print "PJSUA destroying.."
  663. py_pjsua.destroy()