| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
import py_pjsua |
|---|
| 9 |
import sys |
|---|
| 10 |
import thread |
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
THIS_FILE = "pjsua_app.py" |
|---|
| 16 |
C_QUIT = 0 |
|---|
| 17 |
C_LOG_LEVEL = 4 |
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
C_STUN_HOST = "" |
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
C_SIP_PORT = 5060 |
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
g_ua_cfg = None |
|---|
| 33 |
g_acc_id = py_pjsua.PJSUA_INVALID_ID |
|---|
| 34 |
g_current_call = py_pjsua.PJSUA_INVALID_ID |
|---|
| 35 |
g_wav_files = [] |
|---|
| 36 |
g_wav_id = 0 |
|---|
| 37 |
g_wav_port = 0 |
|---|
| 38 |
g_rec_file = "" |
|---|
| 39 |
g_rec_id = 0 |
|---|
| 40 |
g_rec_port = 0 |
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 |
def err_exit(title, rc): |
|---|
| 45 |
py_pjsua.perror(THIS_FILE, title, rc) |
|---|
| 46 |
py_pjsua.destroy() |
|---|
| 47 |
exit(1) |
|---|
| 48 |
|
|---|
| 49 |
|
|---|
| 50 |
|
|---|
| 51 |
|
|---|
| 52 |
def log_cb(level, str, len): |
|---|
| 53 |
if level <= C_LOG_LEVEL: |
|---|
| 54 |
print str, |
|---|
| 55 |
|
|---|
| 56 |
def write_log(level, str): |
|---|
| 57 |
log_cb(level, str + "\n", 0) |
|---|
| 58 |
|
|---|
| 59 |
|
|---|
| 60 |
|
|---|
| 61 |
|
|---|
| 62 |
def call_name(call_id): |
|---|
| 63 |
ci = py_pjsua.call_get_info(call_id) |
|---|
| 64 |
return "[Call " + `call_id` + " " + ci.remote_info + "]" |
|---|
| 65 |
|
|---|
| 66 |
|
|---|
| 67 |
|
|---|
| 68 |
def 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`) |
|---|
| 72 |
if ci.state == py_pjsua.PJSIP_INV_STATE_DISCONNECTED: |
|---|
| 73 |
g_current_call = py_pjsua.PJSUA_INVALID_ID |
|---|
| 74 |
|
|---|
| 75 |
|
|---|
| 76 |
|
|---|
| 77 |
def on_incoming_call(acc_id, call_id, rdata): |
|---|
| 78 |
global g_current_call |
|---|
| 79 |
|
|---|
| 80 |
if g_current_call != py_pjsua.PJSUA_INVALID_ID: |
|---|
| 81 |
|
|---|
| 82 |
py_pjsua.call_answer(call_id, 486, None, None) |
|---|
| 83 |
return |
|---|
| 84 |
|
|---|
| 85 |
g_current_call = call_id |
|---|
| 86 |
ci = py_pjsua.call_get_info(call_id) |
|---|
| 87 |
write_log(3, "*** Incoming call: " + call_name(call_id) + "***") |
|---|
| 88 |
write_log(3, "*** Press a to answer or h to hangup ***") |
|---|
| 89 |
|
|---|
| 90 |
|
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
|
|---|
| 94 |
def on_call_media_state(call_id): |
|---|
| 95 |
ci = py_pjsua.call_get_info(call_id) |
|---|
| 96 |
if ci.media_status == py_pjsua.PJSUA_CALL_MEDIA_ACTIVE: |
|---|
| 97 |
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 |
|
|---|
| 104 |
|
|---|
| 105 |
|
|---|
| 106 |
def on_reg_state(acc_id): |
|---|
| 107 |
acc_info = py_pjsua.acc_get_info(acc_id) |
|---|
| 108 |
if acc_info.has_registration != 0: |
|---|
| 109 |
cmd = "registration" |
|---|
| 110 |
else: |
|---|
| 111 |
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") |
|---|
| 116 |
|
|---|
| 117 |
|
|---|
| 118 |
|
|---|
| 119 |
|
|---|
| 120 |
def 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`) |
|---|
| 127 |
|
|---|
| 128 |
|
|---|
| 129 |
|
|---|
| 130 |
def on_pager(call_id, strfrom, strto, contact, mime_type, text): |
|---|
| 131 |
write_log(3, "MESSAGE from " + `strfrom` + " : " + `text`) |
|---|
| 132 |
|
|---|
| 133 |
|
|---|
| 134 |
|
|---|
| 135 |
|
|---|
| 136 |
def on_pager_status(call_id, strto, body, user_data, status, reason): |
|---|
| 137 |
write_log(3, "MESSAGE to " + `strto` + " status " + `status` + " reason " + `reason`) |
|---|
| 138 |
|
|---|
| 139 |
|
|---|
| 140 |
|
|---|
| 141 |
|
|---|
| 142 |
def 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 |
|
|---|
| 150 |
|
|---|
| 151 |
|
|---|
| 152 |
def 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 |
|
|---|
| 164 |
|
|---|
| 165 |
|
|---|
| 166 |
def on_call_transfer_request(call_id, dst, code): |
|---|
| 167 |
write_log(3, "Call transfer request from " + `call_id` + " to " + dst + " with code " + `code`) |
|---|
| 168 |
|
|---|
| 169 |
|
|---|
| 170 |
|
|---|
| 171 |
|
|---|
| 172 |
def app_init(): |
|---|
| 173 |
global g_acc_id, g_ua_cfg |
|---|
| 174 |
|
|---|
| 175 |
|
|---|
| 176 |
status = py_pjsua.create() |
|---|
| 177 |
if status != 0: |
|---|
| 178 |
err_exit("pjsua create() error", status) |
|---|
| 179 |
|
|---|
| 180 |
|
|---|
| 181 |
log_cfg = py_pjsua.logging_config_default() |
|---|
| 182 |
log_cfg.level = C_LOG_LEVEL |
|---|
| 183 |
log_cfg.cb = log_cb |
|---|
| 184 |
|
|---|
| 185 |
|
|---|
| 186 |
|
|---|
| 187 |
|
|---|
| 188 |
|
|---|
| 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 |
|---|
| 196 |
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 |
|---|
| 199 |
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 |
|---|
| 202 |
|
|---|
| 203 |
|
|---|
| 204 |
if C_STUN_HOST != "": |
|---|
| 205 |
ua_cfg.stun_host = C_STUN_HOST; |
|---|
| 206 |
|
|---|
| 207 |
|
|---|
| 208 |
med_cfg = py_pjsua.media_config_default() |
|---|
| 209 |
med_cfg.ec_tail_len = 0 |
|---|
| 210 |
|
|---|
| 211 |
|
|---|
| 212 |
|
|---|
| 213 |
|
|---|
| 214 |
status = py_pjsua.init(ua_cfg, log_cfg, med_cfg) |
|---|
| 215 |
if status != 0: |
|---|
| 216 |
err_exit("pjsua init() error", status) |
|---|
| 217 |
|
|---|
| 218 |
|
|---|
| 219 |
transport_cfg = py_pjsua.transport_config_default() |
|---|
| 220 |
transport_cfg.port = C_SIP_PORT |
|---|
| 221 |
|
|---|
| 222 |
|
|---|
| 223 |
status, transport_id = \ |
|---|
| 224 |
py_pjsua.transport_create(py_pjsua.PJSIP_TRANSPORT_UDP, transport_cfg) |
|---|
| 225 |
if status != 0: |
|---|
| 226 |
err_exit("Error creating UDP transport", status) |
|---|
| 227 |
|
|---|
| 228 |
|
|---|
| 229 |
|
|---|
| 230 |
status, acc_id = py_pjsua.acc_add_local(transport_id, 1) |
|---|
| 231 |
if status != 0: |
|---|
| 232 |
err_exit("Error creating account", status) |
|---|
| 233 |
|
|---|
| 234 |
g_acc_id = acc_id |
|---|
| 235 |
g_ua_cfg = ua_cfg |
|---|
| 236 |
|
|---|
| 237 |
|
|---|
| 238 |
|
|---|
| 239 |
def add_account(): |
|---|
| 240 |
global g_acc_id |
|---|
| 241 |
|
|---|
| 242 |
acc_domain = "" |
|---|
| 243 |
acc_username = "" |
|---|
| 244 |
acc_passwd ="" |
|---|
| 245 |
confirm = "" |
|---|
| 246 |
|
|---|
| 247 |
|
|---|
| 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 |
|
|---|
| 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 |
|---|
| 270 |
|
|---|
| 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 |
|---|
| 280 |
|
|---|
| 281 |
|
|---|
| 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") |
|---|
| 288 |
|
|---|
| 289 |
def 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 |
|
|---|
| 313 |
def 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") |
|---|
| 335 |
|
|---|
| 336 |
def conf_list(): |
|---|
| 337 |
ports = None |
|---|
| 338 |
print "Conference ports : " |
|---|
| 339 |
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 = "" |
|---|
| 345 |
for listener in info.listeners: |
|---|
| 346 |
txlist = txlist + "#" + `listener` + " " |
|---|
| 347 |
|
|---|
| 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 |
|
|---|
| 350 |
def 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 |
|
|---|
| 372 |
def 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 |
|
|---|
| 394 |
def 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") |
|---|
| 403 |
|
|---|
| 404 |
def 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 |
|
|---|
| 430 |
def 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 |
|
|---|
| 474 |
|
|---|
| 475 |
|
|---|
| 476 |
|
|---|
| 477 |
|
|---|
| 478 |
|
|---|
| 479 |
|
|---|
| 480 |
def worker_thread_main(arg): |
|---|
| 481 |
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 |
|
|---|
| 492 |
|
|---|
| 493 |
|
|---|
| 494 |
|
|---|
| 495 |
def app_start(): |
|---|
| 496 |
|
|---|
| 497 |
|
|---|
| 498 |
status = py_pjsua.start() |
|---|
| 499 |
if status != 0: |
|---|
| 500 |
err_exit("Error starting pjsua!", status) |
|---|
| 501 |
|
|---|
| 502 |
|
|---|
| 503 |
thr = thread.start_new(worker_thread_main, (0,)) |
|---|
| 504 |
|
|---|
| 505 |
print "PJSUA Started!!" |
|---|
| 506 |
|
|---|
| 507 |
|
|---|
| 508 |
|
|---|
| 509 |
def 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 |
|
|---|
| 542 |
|
|---|
| 543 |
|
|---|
| 544 |
def print_menu(): |
|---|
| 545 |
print "" |
|---|
| 546 |
print ">>>" |
|---|
| 547 |
print_acc_buddy_list() |
|---|
| 548 |
print """ |
|---|
| 549 |
+============================================================================+ |
|---|
| 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 | |
|---|
| 563 |
| | cc Connect port | dd Dump detail | |
|---|
| 564 |
| | cd Disconnect port | | |
|---|
| 565 |
| | +p Add file player | | |
|---|
| 566 |
|------------------------------+ +r Add file recorder | | |
|---|
| 567 |
| q Quit application | | | |
|---|
| 568 |
+============================================================================+""" |
|---|
| 569 |
print "You have " + `py_pjsua.call_get_count()` + " active call(s)" |
|---|
| 570 |
print ">>>", |
|---|
| 571 |
|
|---|
| 572 |
|
|---|
| 573 |
|
|---|
| 574 |
def app_menu(): |
|---|
| 575 |
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 |
|
|---|
| 588 |
print "Send IM to SIP URL: ", |
|---|
| 589 |
url = sys.stdin.readline() |
|---|
| 590 |
if url == "\n": |
|---|
| 591 |
continue |
|---|
| 592 |
|
|---|
| 593 |
|
|---|
| 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 |
|
|---|
| 603 |
py_pjsua.im_send(g_acc_id, url, None, message, None, 0) |
|---|
| 604 |
|
|---|
| 605 |
elif choice[0] == "m": |
|---|
| 606 |
|
|---|
| 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 |
|
|---|
| 615 |
status, call_id = py_pjsua.call_make_call(g_acc_id, url, 0, 0, None) |
|---|
| 616 |
|
|---|
| 617 |
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 |
|
|---|
| 624 |
bc = py_pjsua.Buddy_Config() |
|---|
| 625 |
print "Buddy URL: ", |
|---|
| 626 |
bc.uri = sys.stdin.readline() |
|---|
| 627 |
if bc.uri == "\n": |
|---|
| 628 |
continue |
|---|
| 629 |
|
|---|
| 630 |
bc.uri = bc.uri.replace("\n", "") |
|---|
| 631 |
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) |
|---|
| 635 |
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" |
|---|
| 647 |
elif choice[0] == "+" and choice[1] == "a": |
|---|
| 648 |
|
|---|
| 649 |
add_account() |
|---|
| 650 |
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) |
|---|
| 657 |
|
|---|
| 658 |
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() |
|---|
| 680 |
elif choice[0] == "h": |
|---|
| 681 |
if g_current_call != py_pjsua.PJSUA_INVALID_ID: |
|---|
| 682 |
py_pjsua.call_hangup(g_current_call, 603, None, None) |
|---|
| 683 |
else: |
|---|
| 684 |
print "No current call" |
|---|
| 685 |
elif choice[0] == "H": |
|---|
| 686 |
if g_current_call != py_pjsua.PJSUA_INVALID_ID: |
|---|
| 687 |
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 |
i |
|---|