Changeset 3763 for pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
- Timestamp:
- Sep 21, 2011 10:20:01 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
r3753 r3763 711 711 pjsua_var.media_cfg.rx_drop_pct); 712 712 713 call_med->tp_ready = PJ_SUCCESS; 714 713 715 return PJ_SUCCESS; 714 716 … … 772 774 switch (op) { 773 775 case PJ_ICE_STRANS_OP_INIT: 774 call_med->tp_ready = result; 776 call_med->tp_ready = result; 777 if (call_med->med_create_cb) 778 (*call_med->med_create_cb)(call_med, result, 779 call_med->call->secure_level, NULL); 775 780 break; 776 781 case PJ_ICE_STRANS_OP_NEGOTIATION: … … 832 837 call_med->call->index, call_med->idx)); 833 838 } 839 if (pjsua_var.ua_cfg.cb.on_call_media_transport_state) { 840 pjsua_med_tp_state_info info; 841 842 pj_bzero(&info, sizeof(info)); 843 info.med_idx = call_med->idx; 844 info.state = call_med->tp_st; 845 info.status = result; 846 info.ext_info = &op; 847 (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)( 848 call_med->call->index, &info); 849 } 834 850 if (pjsua_var.ua_cfg.cb.on_ice_transport_error) { 835 851 pjsua_call_id id = call_med->call->index; … … 871 887 static pj_status_t create_ice_media_transport( 872 888 const pjsua_transport_config *cfg, 873 pjsua_call_media *call_med) 889 pjsua_call_media *call_med, 890 pj_bool_t async) 874 891 { 875 892 char stunip[PJ_INET6_ADDRSTRLEN]; … … 953 970 954 971 /* Wait until transport is initialized, or time out */ 955 PJSUA_UNLOCK(); 956 while (call_med->tp_ready == PJ_EPENDING) { 957 pjsua_handle_events(100); 958 } 959 PJSUA_LOCK(); 960 if (call_med->tp_ready != PJ_SUCCESS) { 972 if (!async) { 973 PJSUA_UNLOCK(); 974 while (call_med->tp_ready == PJ_EPENDING) { 975 pjsua_handle_events(100); 976 } 977 PJSUA_LOCK(); 978 } 979 980 if (async && call_med->tp_ready == PJ_EPENDING) { 981 return PJ_EPENDING; 982 } else if (call_med->tp_ready != PJ_SUCCESS) { 961 983 pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 962 984 call_med->tp_ready); … … 1236 1258 } 1237 1259 1260 /* Set media transport state and notify the application via the callback. */ 1261 void set_media_tp_state(pjsua_call_media *call_med, 1262 pjsua_med_tp_st tp_st) 1263 { 1264 if (pjsua_var.ua_cfg.cb.on_call_media_transport_state && 1265 call_med->tp_st != tp_st) 1266 { 1267 pjsua_med_tp_state_info info; 1268 1269 pj_bzero(&info, sizeof(info)); 1270 info.med_idx = call_med->idx; 1271 info.state = tp_st; 1272 info.status = call_med->tp_ready; 1273 (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)( 1274 call_med->call->index, &info); 1275 } 1276 1277 call_med->tp_st = tp_st; 1278 } 1279 1280 /* Callback to resume pjsua_call_media_init() after media transport 1281 * creation is completed. 1282 */ 1283 static pj_status_t call_media_init_cb(pjsua_call_media *call_med, 1284 pj_status_t status, 1285 int security_level, 1286 int *sip_err_code) 1287 { 1288 pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; 1289 int err_code = 0; 1290 1291 if (status != PJ_SUCCESS) 1292 goto on_error; 1293 1294 if (call_med->tp_st == PJSUA_MED_TP_CREATING) 1295 set_media_tp_state(call_med, PJSUA_MED_TP_IDLE); 1296 1297 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1298 /* This function may be called when SRTP transport already exists 1299 * (e.g: in re-invite, update), don't need to destroy/re-create. 1300 */ 1301 if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) { 1302 pjmedia_srtp_setting srtp_opt; 1303 pjmedia_transport *srtp = NULL; 1304 1305 /* Check if SRTP requires secure signaling */ 1306 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 1307 if (security_level < acc->cfg.srtp_secure_signaling) { 1308 err_code = PJSIP_SC_NOT_ACCEPTABLE; 1309 status = PJSIP_ESESSIONINSECURE; 1310 goto on_error; 1311 } 1312 } 1313 1314 /* Always create SRTP adapter */ 1315 pjmedia_srtp_setting_default(&srtp_opt); 1316 srtp_opt.close_member_tp = PJ_TRUE; 1317 /* If media session has been ever established, let's use remote's 1318 * preference in SRTP usage policy, especially when it is stricter. 1319 */ 1320 if (call_med->rem_srtp_use > acc->cfg.use_srtp) 1321 srtp_opt.use = call_med->rem_srtp_use; 1322 else 1323 srtp_opt.use = acc->cfg.use_srtp; 1324 1325 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 1326 call_med->tp, 1327 &srtp_opt, &srtp); 1328 if (status != PJ_SUCCESS) { 1329 err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1330 goto on_error; 1331 } 1332 1333 /* Set SRTP as current media transport */ 1334 call_med->tp_orig = call_med->tp; 1335 call_med->tp = srtp; 1336 } 1337 #else 1338 call_med->tp_orig = call_med->tp; 1339 PJ_UNUSED_ARG(security_level); 1340 #endif 1341 1342 pjmedia_event_subscription_init(&call_med->esub_rend, &call_media_on_event, 1343 call_med); 1344 pjmedia_event_subscription_init(&call_med->esub_cap, &call_media_on_event, 1345 call_med); 1346 1347 on_error: 1348 if (status != PJ_SUCCESS && call_med->tp) { 1349 pjmedia_transport_close(call_med->tp); 1350 call_med->tp = NULL; 1351 } 1352 1353 if (sip_err_code) 1354 *sip_err_code = err_code; 1355 1356 if (call_med->med_init_cb) { 1357 pjsua_med_tp_state_info info; 1358 1359 pj_bzero(&info, sizeof(info)); 1360 info.status = status; 1361 info.state = call_med->tp_st; 1362 info.med_idx = call_med->idx; 1363 info.sip_err_code = err_code; 1364 (*call_med->med_init_cb)(call_med->call->index, &info); 1365 } 1366 1367 return status; 1368 } 1369 1238 1370 /* Initialize the media line */ 1239 1371 pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, … … 1241 1373 const pjsua_transport_config *tcfg, 1242 1374 int security_level, 1243 int *sip_err_code) 1375 int *sip_err_code, 1376 pj_bool_t async, 1377 pjsua_med_tp_state_cb cb) 1244 1378 { 1245 1379 pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; 1246 pj_status_t status ;1380 pj_status_t status = PJ_SUCCESS; 1247 1381 1248 1382 /* … … 1252 1386 call_med->type = type; 1253 1387 1254 /* Create the media transport for initial call. This is blocking for now*/1388 /* Create the media transport for initial call. */ 1255 1389 if (call_med->tp == NULL) { 1256 if (pjsua_var.media_cfg.enable_ice) {1257 status = create_ice_media_transport(tcfg, call_med);1258 } else {1259 status = create_udp_media_transport(tcfg, call_med);1260 }1261 1262 if (status != PJ_SUCCESS) {1263 PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport"));1264 return status;1265 }1266 1267 call_med->tp_st = PJSUA_MED_TP_IDLE;1268 1269 1390 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) 1270 1391 /* While in initial call, set default video devices */ … … 1285 1406 #endif 1286 1407 1408 set_media_tp_state(call_med, PJSUA_MED_TP_CREATING); 1409 1410 if (async) { 1411 call_med->med_create_cb = &call_media_init_cb; 1412 call_med->med_init_cb = cb; 1413 } 1414 1415 if (pjsua_var.media_cfg.enable_ice) { 1416 status = create_ice_media_transport(tcfg, call_med, async); 1417 } else { 1418 status = create_udp_media_transport(tcfg, call_med); 1419 } 1420 1421 if (status == PJ_EPENDING) { 1422 /* We will resume call media initialization in the 1423 * on_ice_complete() callback. 1424 */ 1425 return PJ_EPENDING; 1426 } else if (status != PJ_SUCCESS) { 1427 PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport")); 1428 return status; 1429 } 1430 1431 /* Media transport creation completed immediately, so 1432 * we don't need to call the callback. 1433 */ 1434 call_med->med_init_cb = NULL; 1435 1287 1436 } else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) { 1288 1437 /* Media is being reenabled. */ 1289 call_med->tp_st = PJSUA_MED_TP_INIT; 1290 } 1291 1292 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1293 /* This function may be called when SRTP transport already exists 1294 * (e.g: in re-invite, update), don't need to destroy/re-create. 1295 */ 1296 if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) { 1297 pjmedia_srtp_setting srtp_opt; 1298 pjmedia_transport *srtp = NULL; 1299 1300 /* Check if SRTP requires secure signaling */ 1301 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 1302 if (security_level < acc->cfg.srtp_secure_signaling) { 1303 if (sip_err_code) 1304 *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1305 status = PJSIP_ESESSIONINSECURE; 1438 set_media_tp_state(call_med, PJSUA_MED_TP_INIT); 1439 } 1440 1441 return call_media_init_cb(call_med, status, security_level, 1442 sip_err_code); 1443 } 1444 1445 /* Callback to resume pjsua_media_channel_init() after media transport 1446 * initialization is completed. 1447 */ 1448 static pj_status_t media_channel_init_cb(pjsua_call_id call_id, 1449 const pjsua_med_tp_state_info *info) 1450 { 1451 pjsua_call *call = &pjsua_var.calls[call_id]; 1452 pj_status_t status = (info? info->status : PJ_SUCCESS); 1453 unsigned mi; 1454 1455 if (info) { 1456 pj_mutex_lock(call->med_ch_mutex); 1457 1458 /* Set the callback to NULL to indicate that the async operation 1459 * has completed. 1460 */ 1461 call->media[info->med_idx].med_init_cb = NULL; 1462 1463 /* In case of failure, save the information to be returned 1464 * by the last media transport to finish. 1465 */ 1466 if (info->status != PJ_SUCCESS) 1467 pj_memcpy(&call->med_ch_info, info, sizeof(info)); 1468 1469 /* Check whether all the call's medias have finished calling their 1470 * callbacks. 1471 */ 1472 for (mi=0; mi < call->med_cnt; ++mi) { 1473 pjsua_call_media *call_med = &call->media[mi]; 1474 1475 if (call_med->med_init_cb) { 1476 pj_mutex_unlock(call->med_ch_mutex); 1477 return PJ_SUCCESS; 1478 } 1479 1480 if (call_med->tp_ready != PJ_SUCCESS) 1481 status = call_med->tp_ready; 1482 } 1483 1484 /* OK, we are called by the last media transport finished. */ 1485 pj_mutex_unlock(call->med_ch_mutex); 1486 } 1487 1488 if (call->med_ch_mutex) { 1489 pj_mutex_destroy(call->med_ch_mutex); 1490 call->med_ch_mutex = NULL; 1491 } 1492 1493 if (status != PJ_SUCCESS) { 1494 pjsua_media_channel_deinit(call_id); 1495 goto on_error; 1496 } 1497 1498 /* Tell the media transport of a new offer/answer session */ 1499 for (mi=0; mi < call->med_cnt; ++mi) { 1500 pjsua_call_media *call_med = &call->media[mi]; 1501 1502 /* Note: tp may be NULL if this media line is disabled */ 1503 if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) { 1504 pj_pool_t *tmp_pool = (call->inv? call->inv->pool_prov: 1505 call->async_call.dlg->pool); 1506 1507 status = pjmedia_transport_media_create( 1508 call_med->tp, tmp_pool, 1509 0, call->async_call.rem_sdp, mi); 1510 if (status != PJ_SUCCESS) { 1511 call->med_ch_info.status = status; 1512 call->med_ch_info.med_idx = mi; 1513 call->med_ch_info.state = call_med->tp_st; 1514 call->med_ch_info.sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1515 pjsua_media_channel_deinit(call_id); 1306 1516 goto on_error; 1307 1517 } 1308 } 1309 1310 /* Always create SRTP adapter */ 1311 pjmedia_srtp_setting_default(&srtp_opt); 1312 srtp_opt.close_member_tp = PJ_TRUE; 1313 /* If media session has been ever established, let's use remote's 1314 * preference in SRTP usage policy, especially when it is stricter. 1315 */ 1316 if (call_med->rem_srtp_use > acc->cfg.use_srtp) 1317 srtp_opt.use = call_med->rem_srtp_use; 1318 else 1319 srtp_opt.use = acc->cfg.use_srtp; 1320 1321 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 1322 call_med->tp, 1323 &srtp_opt, &srtp); 1324 if (status != PJ_SUCCESS) { 1325 if (sip_err_code) 1326 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1327 goto on_error; 1328 } 1329 1330 /* Set SRTP as current media transport */ 1331 call_med->tp_orig = call_med->tp; 1332 call_med->tp = srtp; 1333 } 1334 #else 1335 call_med->tp_orig = call_med->tp; 1336 PJ_UNUSED_ARG(security_level); 1337 #endif 1338 1339 pjmedia_event_subscription_init(&call_med->esub_rend, &call_media_on_event, 1340 call_med); 1341 pjmedia_event_subscription_init(&call_med->esub_cap, &call_media_on_event, 1342 call_med); 1343 1344 return PJ_SUCCESS; 1518 1519 set_media_tp_state(call_med, PJSUA_MED_TP_INIT); 1520 } 1521 } 1522 1523 call->med_ch_info.status = PJ_SUCCESS; 1345 1524 1346 1525 on_error: 1347 if (call_med->tp) { 1348 pjmedia_transport_close(call_med->tp); 1349 call_med->tp = NULL; 1350 } 1526 if (call->med_ch_cb) 1527 (*call->med_ch_cb)(call->index, &call->med_ch_info); 1528 1351 1529 return status; 1352 1530 } … … 1357 1535 pj_pool_t *tmp_pool, 1358 1536 const pjmedia_sdp_session *rem_sdp, 1359 int *sip_err_code) 1537 int *sip_err_code, 1538 pj_bool_t async, 1539 pjsua_med_tp_state_cb cb) 1360 1540 { 1361 1541 const pj_str_t STR_AUDIO = { "audio", 5 }; … … 1369 1549 pjmedia_type media_types[PJSUA_MAX_CALL_MEDIA]; 1370 1550 unsigned mi; 1551 pj_bool_t pending_med_tp = PJ_FALSE; 1371 1552 pj_status_t status; 1372 1553 1373 1554 PJ_UNUSED_ARG(role); 1555 PJ_UNUSED_ARG(tmp_pool); 1374 1556 1375 1557 /* … … 1380 1562 if (pjsua_get_state() != PJSUA_STATE_RUNNING) 1381 1563 return PJ_EBUSY; 1564 1565 if (async) { 1566 pj_pool_t *tmppool = (call->inv? call->inv->pool_prov: 1567 call->async_call.dlg->pool); 1568 1569 status = pj_mutex_create_simple(tmppool, NULL, &call->med_ch_mutex); 1570 if (status != PJ_SUCCESS) 1571 return status; 1572 } 1382 1573 1383 1574 PJ_LOG(4,(THIS_FILE, "Call %d: initializing media..", call_id)); … … 1450 1641 status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 1451 1642 goto on_error; 1643 } 1644 1645 if (async) { 1646 call->med_ch_cb = cb; 1647 if (rem_sdp) { 1648 /* TODO: change rem_sdp to non-const parameter. */ 1649 call->async_call.rem_sdp = 1650 pjmedia_sdp_session_clone(call->inv->pool_prov, rem_sdp); 1651 } 1452 1652 } 1453 1653 … … 1483 1683 status = pjsua_call_media_init(call_med, media_type, 1484 1684 &acc->cfg.rtp_cfg, 1485 security_level, sip_err_code); 1486 if (status != PJ_SUCCESS) { 1487 pjsua_media_channel_deinit(call_id); 1685 security_level, sip_err_code, 1686 async, 1687 (async? (pjsua_med_tp_state_cb) 1688 &media_channel_init_cb: NULL)); 1689 if (status == PJ_EPENDING) { 1690 pending_med_tp = PJ_TRUE; 1691 } else if (status != PJ_SUCCESS) { 1692 if (pending_med_tp) { 1693 /* Save failure information. */ 1694 call_med->tp_ready = status; 1695 pj_bzero(&call->med_ch_info, sizeof(call->med_ch_info)); 1696 call->med_ch_info.status = status; 1697 call->med_ch_info.state = call_med->tp_st; 1698 call->med_ch_info.med_idx = call_med->idx; 1699 if (sip_err_code) 1700 call->med_ch_info.sip_err_code = *sip_err_code; 1701 1702 /* We will return failure in the callback later. */ 1703 return PJ_EPENDING; 1704 } 1705 1706 pjsua_media_channel_deinit(call_id); 1488 1707 goto on_error; 1489 1708 } … … 1499 1718 pj_assert(call_med->tp_st == PJSUA_MED_TP_INIT || 1500 1719 call_med->tp_st == PJSUA_MED_TP_RUNNING); 1501 call_med->tp_st = PJSUA_MED_TP_DISABLED;1720 set_media_tp_state(call_med, PJSUA_MED_TP_DISABLED); 1502 1721 } 1503 1722 … … 1512 1731 call->audio_idx, call->index)); 1513 1732 1514 /* Tell the media transport of a new offer/answer session */ 1515 for (mi=0; mi < call->med_cnt; ++mi) { 1516 pjsua_call_media *call_med = &call->media[mi]; 1517 1518 /* Note: tp may be NULL if this media line is disabled */ 1519 if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) { 1520 status = pjmedia_transport_media_create(call_med->tp, 1521 tmp_pool, 0, 1522 rem_sdp, mi); 1523 if (status != PJ_SUCCESS) { 1524 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1525 pjsua_media_channel_deinit(call_id); 1526 goto on_error; 1527 } 1528 1529 call_med->tp_st = PJSUA_MED_TP_INIT; 1530 } 1531 } 1733 if (pending_med_tp) { 1734 /* We have a pending media transport initialization. */ 1735 pj_log_pop_indent(); 1736 return PJ_EPENDING; 1737 } 1738 1739 /* Media transport initialization completed immediately, so 1740 * we don't need to call the callback. 1741 */ 1742 call->med_ch_cb = NULL; 1743 1744 status = media_channel_init_cb(call_id, NULL); 1745 if (status != PJ_SUCCESS && sip_err_code) 1746 *sip_err_code = call->med_ch_info.sip_err_code; 1532 1747 1533 1748 pj_log_pop_indent(); 1534 return PJ_SUCCESS;1749 return status; 1535 1750 1536 1751 on_error: 1752 if (call->med_ch_mutex) { 1753 pj_mutex_destroy(call->med_ch_mutex); 1754 call->med_ch_mutex = NULL; 1755 } 1756 1537 1757 pj_log_pop_indent(); 1538 1758 return status; … … 1563 1783 status = pjsua_media_channel_init(call_id, PJSIP_ROLE_UAS, 1564 1784 call->secure_level, pool, 1565 rem_sdp, sip_err_code); 1785 rem_sdp, sip_err_code, 1786 PJ_FALSE, NULL); 1566 1787 if (status != PJ_SUCCESS) 1567 1788 return status; … … 1886 2107 pjsua_call_media *call_med = &call->media[mi]; 1887 2108 1888 if (call_med->tp_st !=PJSUA_MED_TP_IDLE) {2109 if (call_med->tp_st > PJSUA_MED_TP_IDLE) { 1889 2110 pjmedia_transport_media_stop(call_med->tp); 1890 call_med->tp_st = PJSUA_MED_TP_IDLE;2111 set_media_tp_state(call_med, PJSUA_MED_TP_IDLE); 1891 2112 } 1892 2113 … … 1972 2193 goto on_return; 1973 2194 1974 call_med->tp_st = PJSUA_MED_TP_RUNNING;2195 set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING); 1975 2196 1976 2197 /* Get remote SRTP usage policy */ … … 2264 2485 pjmedia_transport_close(call_med->tp); 2265 2486 call_med->tp = call_med->tp_orig = NULL; 2266 call_med->tp_st = PJSUA_MED_TP_IDLE;2487 set_media_tp_state(call_med, PJSUA_MED_TP_IDLE); 2267 2488 } 2268 2489
Note: See TracChangeset
for help on using the changeset viewer.