Changeset 3664 for pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
- Timestamp:
- Jul 19, 2011 3:42:28 AM (13 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk
- Property svn:mergeinfo changed
-
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
r3553 r3664 102 102 { 103 103 pjsua_call *call = &pjsua_var.calls[id]; 104 104 unsigned i; 105 106 pj_bzero(call, sizeof(*call)); 105 107 call->index = id; 106 call->inv = NULL;107 call->user_data = NULL;108 call->session = NULL;109 call->audio_idx = -1;110 call->ssrc = pj_rand();111 call->rtp_tx_seq = 0;112 call->rtp_tx_ts = 0;113 call->rtp_tx_seq_ts_set = 0;114 call->xfer_sub = NULL;115 call->last_code = (pjsip_status_code) 0;116 call->conf_slot = PJSUA_INVALID_ID;117 108 call->last_text.ptr = call->last_text_buf_; 118 call->last_text.slen = 0; 119 call->conn_time.sec = 0; 120 call->conn_time.msec = 0; 121 call->res_time.sec = 0; 122 call->res_time.msec = 0; 123 call->rem_nat_type = PJ_STUN_NAT_TYPE_UNKNOWN; 124 call->rem_srtp_use = PJMEDIA_SRTP_DISABLED; 125 call->local_hold = PJ_FALSE; 126 pj_bzero(&call->lock_codec, sizeof(call->lock_codec)); 109 for (i=0; i<PJ_ARRAY_SIZE(call->media); ++i) { 110 pjsua_call_media *call_med = &call->media[i]; 111 call_med->ssrc = pj_rand(); 112 call_med->strm.a.conf_slot = PJSUA_INVALID_ID; 113 call_med->strm.v.cap_win_id = PJSUA_INVALID_ID; 114 call_med->strm.v.rdr_win_id = PJSUA_INVALID_ID; 115 call_med->call = call; 116 call_med->idx = i; 117 call_med->tp_auto_del = PJ_TRUE; 118 } 127 119 } 128 120 … … 824 816 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS, 825 817 call->secure_level, 826 rdata->tp_info.pool, offer, 818 rdata->tp_info.pool, 819 offer, 827 820 &sip_err_code); 828 821 if (status != PJ_SUCCESS) { … … 1119 1112 PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id) 1120 1113 { 1114 pjsua_call *call = &pjsua_var.calls[call_id]; 1121 1115 PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 1122 1116 PJ_EINVAL); 1123 return pjsua_var.calls[call_id].session != NULL; 1124 } 1125 1126 1127 /* 1128 * Retrieve the media session associated with this call. 1129 */ 1130 PJ_DEF(pjmedia_session*) pjsua_call_get_media_session(pjsua_call_id call_id) 1131 { 1132 PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 1133 NULL); 1134 return pjsua_var.calls[call_id].session; 1135 } 1136 1137 1138 /* 1139 * Retrieve the media transport instance that is used for this call. 1140 */ 1141 PJ_DEF(pjmedia_transport*) pjsua_call_get_media_transport(pjsua_call_id cid) 1142 { 1143 PJ_ASSERT_RETURN(cid>=0 && cid<(int)pjsua_var.ua_cfg.max_calls, 1144 NULL); 1145 return pjsua_var.calls[cid].med_tp; 1117 return call->audio_idx >= 0 && call->media[call->audio_idx].strm.a.stream; 1146 1118 } 1147 1119 … … 1239 1211 return PJSUA_INVALID_ID; 1240 1212 1241 port_id = call-> conf_slot;1213 port_id = call->media[call->audio_idx].strm.a.conf_slot; 1242 1214 1243 1215 pjsip_dlg_dec_lock(dlg); … … 1256 1228 pjsua_call *call; 1257 1229 pjsip_dialog *dlg; 1230 unsigned mi; 1258 1231 pj_status_t status; 1259 1232 … … 1330 1303 } 1331 1304 1332 /* media status and dir */ 1333 info->media_status = call->media_st; 1334 info->media_dir = call->media_dir; 1335 1336 1337 /* conference slot number */ 1338 info->conf_slot = call->conf_slot; 1305 /* Build array of media status and dir */ 1306 info->media_cnt = 0; 1307 for (mi=0; mi < call->med_cnt && 1308 info->media_cnt < PJ_ARRAY_SIZE(info->media); ++mi) 1309 { 1310 pjsua_call_media *call_med = &call->media[mi]; 1311 1312 info->media[info->media_cnt].index = mi; 1313 info->media[info->media_cnt].status = call_med->state; 1314 info->media[info->media_cnt].dir = call_med->dir; 1315 info->media[info->media_cnt].type = call_med->type; 1316 1317 if (call_med->type == PJMEDIA_TYPE_AUDIO) { 1318 info->media[info->media_cnt].stream.aud.conf_slot = 1319 call_med->strm.a.conf_slot; 1320 } else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 1321 pjmedia_vid_dev_index cap_dev = PJMEDIA_VID_INVALID_DEV; 1322 1323 info->media[info->media_cnt].stream.vid.win_in = 1324 call_med->strm.v.rdr_win_id; 1325 1326 if (call_med->strm.v.cap_win_id != PJSUA_INVALID_ID) { 1327 pjsua_vid_win *w = &pjsua_var.win[call_med->strm.v.cap_win_id]; 1328 cap_dev = w->preview_cap_id; 1329 } 1330 info->media[info->media_cnt].stream.vid.cap_dev = cap_dev; 1331 } else { 1332 continue; 1333 } 1334 ++info->media_cnt; 1335 } 1336 1337 if (call->audio_idx != -1) { 1338 info->media_status = call->media[call->audio_idx].state; 1339 info->media_dir = call->media[call->audio_idx].dir; 1340 info->conf_slot = call->media[call->audio_idx].strm.a.conf_slot; 1341 } 1339 1342 1340 1343 /* calculate duration */ … … 1430 1433 *p_type = pjsua_var.calls[call_id].rem_nat_type; 1431 1434 return PJ_SUCCESS; 1435 } 1436 1437 1438 /* 1439 * Get media stream info for the specified media index. 1440 */ 1441 PJ_DEF(pj_status_t) pjsua_call_get_stream_info( pjsua_call_id call_id, 1442 unsigned med_idx, 1443 pjsua_stream_info *psi) 1444 { 1445 pjsua_call *call; 1446 pjsua_call_media *call_med; 1447 pj_status_t status; 1448 1449 PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 1450 PJ_EINVAL); 1451 PJ_ASSERT_RETURN(psi, PJ_EINVAL); 1452 1453 PJSUA_LOCK(); 1454 1455 call = &pjsua_var.calls[call_id]; 1456 1457 if (med_idx >= call->med_cnt) { 1458 PJSUA_UNLOCK(); 1459 return PJ_EINVAL; 1460 } 1461 1462 call_med = &call->media[med_idx]; 1463 psi->type = call_med->type; 1464 switch (call_med->type) { 1465 case PJMEDIA_TYPE_AUDIO: 1466 status = pjmedia_stream_get_info(call_med->strm.a.stream, 1467 &psi->info.aud); 1468 break; 1469 case PJMEDIA_TYPE_VIDEO: 1470 status = pjmedia_vid_stream_get_info(call_med->strm.v.stream, 1471 &psi->info.vid); 1472 break; 1473 default: 1474 status = PJMEDIA_EINVALIMEDIATYPE; 1475 break; 1476 } 1477 1478 PJSUA_UNLOCK(); 1479 return status; 1480 } 1481 1482 1483 /* 1484 * Get media stream statistic for the specified media index. 1485 */ 1486 PJ_DEF(pj_status_t) pjsua_call_get_stream_stat( pjsua_call_id call_id, 1487 unsigned med_idx, 1488 pjsua_stream_stat *stat) 1489 { 1490 pjsua_call *call; 1491 pjsua_call_media *call_med; 1492 pj_status_t status; 1493 1494 PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 1495 PJ_EINVAL); 1496 PJ_ASSERT_RETURN(stat, PJ_EINVAL); 1497 1498 PJSUA_LOCK(); 1499 1500 call = &pjsua_var.calls[call_id]; 1501 1502 if (med_idx >= call->med_cnt) { 1503 PJSUA_UNLOCK(); 1504 return PJ_EINVAL; 1505 } 1506 1507 call_med = &call->media[med_idx]; 1508 switch (call_med->type) { 1509 case PJMEDIA_TYPE_AUDIO: 1510 status = pjmedia_stream_get_stat(call_med->strm.a.stream, 1511 &stat->rtcp); 1512 if (status == PJ_SUCCESS) 1513 status = pjmedia_stream_get_stat_jbuf(call_med->strm.a.stream, 1514 &stat->jbuf); 1515 break; 1516 case PJMEDIA_TYPE_VIDEO: 1517 status = pjmedia_vid_stream_get_stat(call_med->strm.v.stream, 1518 &stat->rtcp); 1519 if (status == PJ_SUCCESS) 1520 status = pjmedia_vid_stream_get_stat_jbuf(call_med->strm.v.stream, 1521 &stat->jbuf); 1522 break; 1523 default: 1524 status = PJMEDIA_EINVALIMEDIATYPE; 1525 break; 1526 } 1527 1528 PJSUA_UNLOCK(); 1529 return status; 1530 } 1531 1532 1533 /* 1534 * Get media transport info for the specified media index. 1535 */ 1536 PJ_DEF(pj_status_t) pjsua_call_get_transport_info( pjsua_call_id call_id, 1537 unsigned med_idx, 1538 pjmedia_transport_info *t) 1539 { 1540 pjsua_call *call; 1541 pjsua_call_media *call_med; 1542 pj_status_t status; 1543 1544 PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 1545 PJ_EINVAL); 1546 PJ_ASSERT_RETURN(t, PJ_EINVAL); 1547 1548 PJSUA_LOCK(); 1549 1550 call = &pjsua_var.calls[call_id]; 1551 1552 if (med_idx >= call->med_cnt) { 1553 PJSUA_UNLOCK(); 1554 return PJ_EINVAL; 1555 } 1556 1557 call_med = &call->media[med_idx]; 1558 1559 pjmedia_transport_info_init(t); 1560 status = pjmedia_transport_get_info(call_med->tp, t); 1561 1562 PJSUA_UNLOCK(); 1563 return status; 1432 1564 } 1433 1565 … … 1974 2106 return status; 1975 2107 1976 if (! call->session) {2108 if (!pjsua_call_has_media(call_id)) { 1977 2109 PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 1978 2110 pjsip_dlg_dec_lock(dlg); … … 1980 2112 } 1981 2113 1982 status = pjmedia_session_dial_dtmf( call->session, 0, digits); 2114 status = pjmedia_stream_dial_dtmf( 2115 call->media[call->audio_idx].strm.a.stream, digits); 1983 2116 1984 2117 pjsip_dlg_dec_lock(dlg); … … 2178 2311 } 2179 2312 2180 2181 const char *good_number(char *buf, pj_int32_t val)2182 {2183 if (val < 1000) {2184 pj_ansi_sprintf(buf, "%d", val);2185 } else if (val < 1000000) {2186 pj_ansi_sprintf(buf, "%d.%dK",2187 val / 1000,2188 (val % 1000) / 100);2189 } else {2190 pj_ansi_sprintf(buf, "%d.%02dM",2191 val / 1000000,2192 (val % 1000000) / 10000);2193 }2194 2195 return buf;2196 }2197 2198 2199 /* Dump media session */2200 static void dump_media_session(const char *indent,2201 char *buf, unsigned maxlen,2202 pjsua_call *call)2203 {2204 unsigned i;2205 char *p = buf, *end = buf+maxlen;2206 int len;2207 pjmedia_session_info info;2208 pjmedia_session *session = call->session;2209 pjmedia_transport_info tp_info;2210 2211 pjmedia_transport_info_init(&tp_info);2212 2213 pjmedia_transport_get_info(call->med_tp, &tp_info);2214 pjmedia_session_get_info(session, &info);2215 2216 for (i=0; i<info.stream_cnt; ++i) {2217 pjmedia_rtcp_stat stat;2218 char rem_addr_buf[80];2219 const char *rem_addr;2220 const char *dir;2221 char last_update[64];2222 char packets[32], bytes[32], ipbytes[32], avg_bps[32], avg_ipbps[32];2223 pj_time_val media_duration, now;2224 2225 pjmedia_session_get_stream_stat(session, i, &stat);2226 // rem_addr will contain actual address of RTP originator, instead of2227 // remote RTP address specified by stream which is fetched from the SDP.2228 // Please note that we are assuming only one stream per call.2229 //rem_addr = pj_sockaddr_print(&info.stream_info[i].rem_addr,2230 // rem_addr_buf, sizeof(rem_addr_buf), 3);2231 if (pj_sockaddr_has_addr(&tp_info.src_rtp_name)) {2232 rem_addr = pj_sockaddr_print(&tp_info.src_rtp_name, rem_addr_buf,2233 sizeof(rem_addr_buf), 3);2234 } else {2235 pj_ansi_snprintf(rem_addr_buf, sizeof(rem_addr_buf), "-");2236 rem_addr = rem_addr_buf;2237 }2238 2239 if (call->media_dir == PJMEDIA_DIR_NONE) {2240 /* To handle when the stream that is currently being paused2241 * (http://trac.pjsip.org/repos/ticket/1079)2242 */2243 dir = "inactive";2244 } else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING)2245 dir = "sendonly";2246 else if (info.stream_info[i].dir == PJMEDIA_DIR_DECODING)2247 dir = "recvonly";2248 else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING)2249 dir = "sendrecv";2250 else2251 dir = "inactive";2252 2253 2254 len = pj_ansi_snprintf(buf, end-p,2255 "%s #%d %.*s @%dKHz, %s, peer=%s",2256 indent, i,2257 (int)info.stream_info[i].fmt.encoding_name.slen,2258 info.stream_info[i].fmt.encoding_name.ptr,2259 info.stream_info[i].fmt.clock_rate / 1000,2260 dir,2261 rem_addr);2262 if (len < 1 || len > end-p) {2263 *p = '\0';2264 return;2265 }2266 2267 p += len;2268 *p++ = '\n';2269 *p = '\0';2270 2271 if (stat.rx.update_cnt == 0)2272 strcpy(last_update, "never");2273 else {2274 pj_gettimeofday(&now);2275 PJ_TIME_VAL_SUB(now, stat.rx.update);2276 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",2277 now.sec / 3600,2278 (now.sec % 3600) / 60,2279 now.sec % 60,2280 now.msec);2281 }2282 2283 pj_gettimeofday(&media_duration);2284 PJ_TIME_VAL_SUB(media_duration, stat.start);2285 if (PJ_TIME_VAL_MSEC(media_duration) == 0)2286 media_duration.msec = 1;2287 2288 /* protect against division by zero */2289 if (stat.rx.pkt == 0)2290 stat.rx.pkt = 1;2291 if (stat.tx.pkt == 0)2292 stat.tx.pkt = 1;2293 2294 len = pj_ansi_snprintf(p, end-p,2295 "%s RX pt=%d, stat last update: %s\n"2296 "%s total %spkt %sB (%sB +IP hdr) @avg=%sbps/%sbps\n"2297 "%s pkt loss=%d (%3.1f%%), discrd=%d (%3.1f%%), dup=%d (%2.1f%%), reord=%d (%3.1f%%)\n"2298 "%s (msec) min avg max last dev\n"2299 "%s loss period: %7.3f %7.3f %7.3f %7.3f %7.3f\n"2300 "%s jitter : %7.3f %7.3f %7.3f %7.3f %7.3f"2301 #if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=02302 "\n"2303 "%s raw jitter : %7.3f %7.3f %7.3f %7.3f %7.3f"2304 #endif2305 #if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=02306 "\n"2307 "%s IPDV : %7.3f %7.3f %7.3f %7.3f %7.3f"2308 #endif2309 "%s",2310 indent, info.stream_info[i].fmt.pt,2311 last_update,2312 indent,2313 good_number(packets, stat.rx.pkt),2314 good_number(bytes, stat.rx.bytes),2315 good_number(ipbytes, stat.rx.bytes + stat.rx.pkt * 40),2316 good_number(avg_bps, (pj_int32_t)((pj_int64_t)stat.rx.bytes * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration))),2317 good_number(avg_ipbps, (pj_int32_t)(((pj_int64_t)stat.rx.bytes + stat.rx.pkt * 40) * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration))),2318 indent,2319 stat.rx.loss,2320 stat.rx.loss * 100.0 / (stat.rx.pkt + stat.rx.loss),2321 stat.rx.discard,2322 stat.rx.discard * 100.0 / (stat.rx.pkt + stat.rx.loss),2323 stat.rx.dup,2324 stat.rx.dup * 100.0 / (stat.rx.pkt + stat.rx.loss),2325 stat.rx.reorder,2326 stat.rx.reorder * 100.0 / (stat.rx.pkt + stat.rx.loss),2327 indent, indent,2328 stat.rx.loss_period.min / 1000.0,2329 stat.rx.loss_period.mean / 1000.0,2330 stat.rx.loss_period.max / 1000.0,2331 stat.rx.loss_period.last / 1000.0,2332 pj_math_stat_get_stddev(&stat.rx.loss_period) / 1000.0,2333 indent,2334 stat.rx.jitter.min / 1000.0,2335 stat.rx.jitter.mean / 1000.0,2336 stat.rx.jitter.max / 1000.0,2337 stat.rx.jitter.last / 1000.0,2338 pj_math_stat_get_stddev(&stat.rx.jitter) / 1000.0,2339 #if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=02340 indent,2341 stat.rx_raw_jitter.min / 1000.0,2342 stat.rx_raw_jitter.mean / 1000.0,2343 stat.rx_raw_jitter.max / 1000.0,2344 stat.rx_raw_jitter.last / 1000.0,2345 pj_math_stat_get_stddev(&stat.rx_raw_jitter) / 1000.0,2346 #endif2347 #if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=02348 indent,2349 stat.rx_ipdv.min / 1000.0,2350 stat.rx_ipdv.mean / 1000.0,2351 stat.rx_ipdv.max / 1000.0,2352 stat.rx_ipdv.last / 1000.0,2353 pj_math_stat_get_stddev(&stat.rx_ipdv) / 1000.0,2354 #endif2355 ""2356 );2357 2358 if (len < 1 || len > end-p) {2359 *p = '\0';2360 return;2361 }2362 2363 p += len;2364 *p++ = '\n';2365 *p = '\0';2366 2367 if (stat.tx.update_cnt == 0)2368 strcpy(last_update, "never");2369 else {2370 pj_gettimeofday(&now);2371 PJ_TIME_VAL_SUB(now, stat.tx.update);2372 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",2373 now.sec / 3600,2374 (now.sec % 3600) / 60,2375 now.sec % 60,2376 now.msec);2377 }2378 2379 len = pj_ansi_snprintf(p, end-p,2380 "%s TX pt=%d, ptime=%dms, stat last update: %s\n"2381 "%s total %spkt %sB (%sB +IP hdr) @avg %sbps/%sbps\n"2382 "%s pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)\n"2383 "%s (msec) min avg max last dev \n"2384 "%s loss period: %7.3f %7.3f %7.3f %7.3f %7.3f\n"2385 "%s jitter : %7.3f %7.3f %7.3f %7.3f %7.3f%s",2386 indent,2387 info.stream_info[i].tx_pt,2388 info.stream_info[i].param->info.frm_ptime *2389 info.stream_info[i].param->setting.frm_per_pkt,2390 last_update,2391 2392 indent,2393 good_number(packets, stat.tx.pkt),2394 good_number(bytes, stat.tx.bytes),2395 good_number(ipbytes, stat.tx.bytes + stat.tx.pkt * 40),2396 good_number(avg_bps, (pj_int32_t)((pj_int64_t)stat.tx.bytes * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration))),2397 good_number(avg_ipbps, (pj_int32_t)(((pj_int64_t)stat.tx.bytes + stat.tx.pkt * 40) * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration))),2398 2399 indent,2400 stat.tx.loss,2401 stat.tx.loss * 100.0 / (stat.tx.pkt + stat.tx.loss),2402 stat.tx.dup,2403 stat.tx.dup * 100.0 / (stat.tx.pkt + stat.tx.loss),2404 stat.tx.reorder,2405 stat.tx.reorder * 100.0 / (stat.tx.pkt + stat.tx.loss),2406 2407 indent, indent,2408 stat.tx.loss_period.min / 1000.0,2409 stat.tx.loss_period.mean / 1000.0,2410 stat.tx.loss_period.max / 1000.0,2411 stat.tx.loss_period.last / 1000.0,2412 pj_math_stat_get_stddev(&stat.tx.loss_period) / 1000.0,2413 indent,2414 stat.tx.jitter.min / 1000.0,2415 stat.tx.jitter.mean / 1000.0,2416 stat.tx.jitter.max / 1000.0,2417 stat.tx.jitter.last / 1000.0,2418 pj_math_stat_get_stddev(&stat.tx.jitter) / 1000.0,2419 ""2420 );2421 2422 if (len < 1 || len > end-p) {2423 *p = '\0';2424 return;2425 }2426 2427 p += len;2428 *p++ = '\n';2429 *p = '\0';2430 2431 len = pj_ansi_snprintf(p, end-p,2432 "%s RTT msec : %7.3f %7.3f %7.3f %7.3f %7.3f",2433 indent,2434 stat.rtt.min / 1000.0,2435 stat.rtt.mean / 1000.0,2436 stat.rtt.max / 1000.0,2437 stat.rtt.last / 1000.0,2438 pj_math_stat_get_stddev(&stat.rtt) / 1000.02439 );2440 if (len < 1 || len > end-p) {2441 *p = '\0';2442 return;2443 }2444 2445 p += len;2446 *p++ = '\n';2447 *p = '\0';2448 2449 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)2450 # define SAMPLES_TO_USEC(usec, samples, clock_rate) \2451 do { \2452 if (samples <= 4294) \2453 usec = samples * 1000000 / clock_rate; \2454 else { \2455 usec = samples * 1000 / clock_rate; \2456 usec *= 1000; \2457 } \2458 } while(0)2459 2460 # define PRINT_VOIP_MTC_VAL(s, v) \2461 if (v == 127) \2462 sprintf(s, "(na)"); \2463 else \2464 sprintf(s, "%d", v)2465 2466 # define VALIDATE_PRINT_BUF() \2467 if (len < 1 || len > end-p) { *p = '\0'; return; } \2468 p += len; *p++ = '\n'; *p = '\0'2469 2470 2471 do {2472 char loss[16], dup[16];2473 char jitter[80];2474 char toh[80];2475 char plc[16], jba[16], jbr[16];2476 char signal_lvl[16], noise_lvl[16], rerl[16];2477 char r_factor[16], ext_r_factor[16], mos_lq[16], mos_cq[16];2478 pjmedia_rtcp_xr_stat xr_stat;2479 unsigned clock_rate;2480 2481 if (pjmedia_session_get_stream_stat_xr(session, i, &xr_stat) !=2482 PJ_SUCCESS)2483 {2484 break;2485 }2486 2487 clock_rate = info.stream_info[i].fmt.clock_rate;2488 2489 len = pj_ansi_snprintf(p, end-p, "\n%s Extended reports:", indent);2490 VALIDATE_PRINT_BUF();2491 2492 /* Statistics Summary */2493 len = pj_ansi_snprintf(p, end-p, "%s Statistics Summary", indent);2494 VALIDATE_PRINT_BUF();2495 2496 if (xr_stat.rx.stat_sum.l)2497 sprintf(loss, "%d", xr_stat.rx.stat_sum.lost);2498 else2499 sprintf(loss, "(na)");2500 2501 if (xr_stat.rx.stat_sum.d)2502 sprintf(dup, "%d", xr_stat.rx.stat_sum.dup);2503 else2504 sprintf(dup, "(na)");2505 2506 if (xr_stat.rx.stat_sum.j) {2507 unsigned jmin, jmax, jmean, jdev;2508 2509 SAMPLES_TO_USEC(jmin, xr_stat.rx.stat_sum.jitter.min,2510 clock_rate);2511 SAMPLES_TO_USEC(jmax, xr_stat.rx.stat_sum.jitter.max,2512 clock_rate);2513 SAMPLES_TO_USEC(jmean, xr_stat.rx.stat_sum.jitter.mean,2514 clock_rate);2515 SAMPLES_TO_USEC(jdev,2516 pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.jitter),2517 clock_rate);2518 sprintf(jitter, "%7.3f %7.3f %7.3f %7.3f",2519 jmin/1000.0, jmean/1000.0, jmax/1000.0, jdev/1000.0);2520 } else2521 sprintf(jitter, "(report not available)");2522 2523 if (xr_stat.rx.stat_sum.t) {2524 sprintf(toh, "%11d %11d %11d %11d",2525 xr_stat.rx.stat_sum.toh.min,2526 xr_stat.rx.stat_sum.toh.mean,2527 xr_stat.rx.stat_sum.toh.max,2528 pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.toh));2529 } else2530 sprintf(toh, "(report not available)");2531 2532 if (xr_stat.rx.stat_sum.update.sec == 0)2533 strcpy(last_update, "never");2534 else {2535 pj_gettimeofday(&now);2536 PJ_TIME_VAL_SUB(now, xr_stat.rx.stat_sum.update);2537 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",2538 now.sec / 3600,2539 (now.sec % 3600) / 60,2540 now.sec % 60,2541 now.msec);2542 }2543 2544 len = pj_ansi_snprintf(p, end-p,2545 "%s RX last update: %s\n"2546 "%s begin seq=%d, end seq=%d\n"2547 "%s pkt loss=%s, dup=%s\n"2548 "%s (msec) min avg max dev\n"2549 "%s jitter : %s\n"2550 "%s toh : %s",2551 indent, last_update,2552 indent,2553 xr_stat.rx.stat_sum.begin_seq, xr_stat.rx.stat_sum.end_seq,2554 indent, loss, dup,2555 indent,2556 indent, jitter,2557 indent, toh2558 );2559 VALIDATE_PRINT_BUF();2560 2561 if (xr_stat.tx.stat_sum.l)2562 sprintf(loss, "%d", xr_stat.tx.stat_sum.lost);2563 else2564 sprintf(loss, "(na)");2565 2566 if (xr_stat.tx.stat_sum.d)2567 sprintf(dup, "%d", xr_stat.tx.stat_sum.dup);2568 else2569 sprintf(dup, "(na)");2570 2571 if (xr_stat.tx.stat_sum.j) {2572 unsigned jmin, jmax, jmean, jdev;2573 2574 SAMPLES_TO_USEC(jmin, xr_stat.tx.stat_sum.jitter.min,2575 clock_rate);2576 SAMPLES_TO_USEC(jmax, xr_stat.tx.stat_sum.jitter.max,2577 clock_rate);2578 SAMPLES_TO_USEC(jmean, xr_stat.tx.stat_sum.jitter.mean,2579 clock_rate);2580 SAMPLES_TO_USEC(jdev,2581 pj_math_stat_get_stddev(&xr_stat.tx.stat_sum.jitter),2582 clock_rate);2583 sprintf(jitter, "%7.3f %7.3f %7.3f %7.3f",2584 jmin/1000.0, jmean/1000.0, jmax/1000.0, jdev/1000.0);2585 } else2586 sprintf(jitter, "(report not available)");2587 2588 if (xr_stat.tx.stat_sum.t) {2589 sprintf(toh, "%11d %11d %11d %11d",2590 xr_stat.tx.stat_sum.toh.min,2591 xr_stat.tx.stat_sum.toh.mean,2592 xr_stat.tx.stat_sum.toh.max,2593 pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.toh));2594 } else2595 sprintf(toh, "(report not available)");2596 2597 if (xr_stat.tx.stat_sum.update.sec == 0)2598 strcpy(last_update, "never");2599 else {2600 pj_gettimeofday(&now);2601 PJ_TIME_VAL_SUB(now, xr_stat.tx.stat_sum.update);2602 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",2603 now.sec / 3600,2604 (now.sec % 3600) / 60,2605 now.sec % 60,2606 now.msec);2607 }2608 2609 len = pj_ansi_snprintf(p, end-p,2610 "%s TX last update: %s\n"2611 "%s begin seq=%d, end seq=%d\n"2612 "%s pkt loss=%s, dup=%s\n"2613 "%s (msec) min avg max dev\n"2614 "%s jitter : %s\n"2615 "%s toh : %s",2616 indent, last_update,2617 indent,2618 xr_stat.tx.stat_sum.begin_seq, xr_stat.tx.stat_sum.end_seq,2619 indent, loss, dup,2620 indent,2621 indent, jitter,2622 indent, toh2623 );2624 VALIDATE_PRINT_BUF();2625 2626 2627 /* VoIP Metrics */2628 len = pj_ansi_snprintf(p, end-p, "%s VoIP Metrics", indent);2629 VALIDATE_PRINT_BUF();2630 2631 PRINT_VOIP_MTC_VAL(signal_lvl, xr_stat.rx.voip_mtc.signal_lvl);2632 PRINT_VOIP_MTC_VAL(noise_lvl, xr_stat.rx.voip_mtc.noise_lvl);2633 PRINT_VOIP_MTC_VAL(rerl, xr_stat.rx.voip_mtc.rerl);2634 PRINT_VOIP_MTC_VAL(r_factor, xr_stat.rx.voip_mtc.r_factor);2635 PRINT_VOIP_MTC_VAL(ext_r_factor, xr_stat.rx.voip_mtc.ext_r_factor);2636 PRINT_VOIP_MTC_VAL(mos_lq, xr_stat.rx.voip_mtc.mos_lq);2637 PRINT_VOIP_MTC_VAL(mos_cq, xr_stat.rx.voip_mtc.mos_cq);2638 2639 switch ((xr_stat.rx.voip_mtc.rx_config>>6) & 3) {2640 case PJMEDIA_RTCP_XR_PLC_DIS:2641 sprintf(plc, "DISABLED");2642 break;2643 case PJMEDIA_RTCP_XR_PLC_ENH:2644 sprintf(plc, "ENHANCED");2645 break;2646 case PJMEDIA_RTCP_XR_PLC_STD:2647 sprintf(plc, "STANDARD");2648 break;2649 case PJMEDIA_RTCP_XR_PLC_UNK:2650 default:2651 sprintf(plc, "UNKNOWN");2652 break;2653 }2654 2655 switch ((xr_stat.rx.voip_mtc.rx_config>>4) & 3) {2656 case PJMEDIA_RTCP_XR_JB_FIXED:2657 sprintf(jba, "FIXED");2658 break;2659 case PJMEDIA_RTCP_XR_JB_ADAPTIVE:2660 sprintf(jba, "ADAPTIVE");2661 break;2662 default:2663 sprintf(jba, "UNKNOWN");2664 break;2665 }2666 2667 sprintf(jbr, "%d", xr_stat.rx.voip_mtc.rx_config & 0x0F);2668 2669 if (xr_stat.rx.voip_mtc.update.sec == 0)2670 strcpy(last_update, "never");2671 else {2672 pj_gettimeofday(&now);2673 PJ_TIME_VAL_SUB(now, xr_stat.rx.voip_mtc.update);2674 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",2675 now.sec / 3600,2676 (now.sec % 3600) / 60,2677 now.sec % 60,2678 now.msec);2679 }2680 2681 len = pj_ansi_snprintf(p, end-p,2682 "%s RX last update: %s\n"2683 "%s packets : loss rate=%d (%.2f%%), discard rate=%d (%.2f%%)\n"2684 "%s burst : density=%d (%.2f%%), duration=%d%s\n"2685 "%s gap : density=%d (%.2f%%), duration=%d%s\n"2686 "%s delay : round trip=%d%s, end system=%d%s\n"2687 "%s level : signal=%s%s, noise=%s%s, RERL=%s%s\n"2688 "%s quality : R factor=%s, ext R factor=%s\n"2689 "%s MOS LQ=%s, MOS CQ=%s\n"2690 "%s config : PLC=%s, JB=%s, JB rate=%s, Gmin=%d\n"2691 "%s JB delay : cur=%d%s, max=%d%s, abs max=%d%s",2692 indent,2693 last_update,2694 /* packets */2695 indent,2696 xr_stat.rx.voip_mtc.loss_rate, xr_stat.rx.voip_mtc.loss_rate*100.0/256,2697 xr_stat.rx.voip_mtc.discard_rate, xr_stat.rx.voip_mtc.discard_rate*100.0/256,2698 /* burst */2699 indent,2700 xr_stat.rx.voip_mtc.burst_den, xr_stat.rx.voip_mtc.burst_den*100.0/256,2701 xr_stat.rx.voip_mtc.burst_dur, "ms",2702 /* gap */2703 indent,2704 xr_stat.rx.voip_mtc.gap_den, xr_stat.rx.voip_mtc.gap_den*100.0/256,2705 xr_stat.rx.voip_mtc.gap_dur, "ms",2706 /* delay */2707 indent,2708 xr_stat.rx.voip_mtc.rnd_trip_delay, "ms",2709 xr_stat.rx.voip_mtc.end_sys_delay, "ms",2710 /* level */2711 indent,2712 signal_lvl, "dB",2713 noise_lvl, "dB",2714 rerl, "",2715 /* quality */2716 indent,2717 r_factor, ext_r_factor,2718 indent,2719 mos_lq, mos_cq,2720 /* config */2721 indent,2722 plc, jba, jbr, xr_stat.rx.voip_mtc.gmin,2723 /* JB delay */2724 indent,2725 xr_stat.rx.voip_mtc.jb_nom, "ms",2726 xr_stat.rx.voip_mtc.jb_max, "ms",2727 xr_stat.rx.voip_mtc.jb_abs_max, "ms"2728 );2729 VALIDATE_PRINT_BUF();2730 2731 PRINT_VOIP_MTC_VAL(signal_lvl, xr_stat.tx.voip_mtc.signal_lvl);2732 PRINT_VOIP_MTC_VAL(noise_lvl, xr_stat.tx.voip_mtc.noise_lvl);2733 PRINT_VOIP_MTC_VAL(rerl, xr_stat.tx.voip_mtc.rerl);2734 PRINT_VOIP_MTC_VAL(r_factor, xr_stat.tx.voip_mtc.r_factor);2735 PRINT_VOIP_MTC_VAL(ext_r_factor, xr_stat.tx.voip_mtc.ext_r_factor);2736 PRINT_VOIP_MTC_VAL(mos_lq, xr_stat.tx.voip_mtc.mos_lq);2737 PRINT_VOIP_MTC_VAL(mos_cq, xr_stat.tx.voip_mtc.mos_cq);2738 2739 switch ((xr_stat.tx.voip_mtc.rx_config>>6) & 3) {2740 case PJMEDIA_RTCP_XR_PLC_DIS:2741 sprintf(plc, "DISABLED");2742 break;2743 case PJMEDIA_RTCP_XR_PLC_ENH:2744 sprintf(plc, "ENHANCED");2745 break;2746 case PJMEDIA_RTCP_XR_PLC_STD:2747 sprintf(plc, "STANDARD");2748 break;2749 case PJMEDIA_RTCP_XR_PLC_UNK:2750 default:2751 sprintf(plc, "unknown");2752 break;2753 }2754 2755 switch ((xr_stat.tx.voip_mtc.rx_config>>4) & 3) {2756 case PJMEDIA_RTCP_XR_JB_FIXED:2757 sprintf(jba, "FIXED");2758 break;2759 case PJMEDIA_RTCP_XR_JB_ADAPTIVE:2760 sprintf(jba, "ADAPTIVE");2761 break;2762 default:2763 sprintf(jba, "unknown");2764 break;2765 }2766 2767 sprintf(jbr, "%d", xr_stat.tx.voip_mtc.rx_config & 0x0F);2768 2769 if (xr_stat.tx.voip_mtc.update.sec == 0)2770 strcpy(last_update, "never");2771 else {2772 pj_gettimeofday(&now);2773 PJ_TIME_VAL_SUB(now, xr_stat.tx.voip_mtc.update);2774 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",2775 now.sec / 3600,2776 (now.sec % 3600) / 60,2777 now.sec % 60,2778 now.msec);2779 }2780 2781 len = pj_ansi_snprintf(p, end-p,2782 "%s TX last update: %s\n"2783 "%s packets : loss rate=%d (%.2f%%), discard rate=%d (%.2f%%)\n"2784 "%s burst : density=%d (%.2f%%), duration=%d%s\n"2785 "%s gap : density=%d (%.2f%%), duration=%d%s\n"2786 "%s delay : round trip=%d%s, end system=%d%s\n"2787 "%s level : signal=%s%s, noise=%s%s, RERL=%s%s\n"2788 "%s quality : R factor=%s, ext R factor=%s\n"2789 "%s MOS LQ=%s, MOS CQ=%s\n"2790 "%s config : PLC=%s, JB=%s, JB rate=%s, Gmin=%d\n"2791 "%s JB delay : cur=%d%s, max=%d%s, abs max=%d%s",2792 indent,2793 last_update,2794 /* pakcets */2795 indent,2796 xr_stat.tx.voip_mtc.loss_rate, xr_stat.tx.voip_mtc.loss_rate*100.0/256,2797 xr_stat.tx.voip_mtc.discard_rate, xr_stat.tx.voip_mtc.discard_rate*100.0/256,2798 /* burst */2799 indent,2800 xr_stat.tx.voip_mtc.burst_den, xr_stat.tx.voip_mtc.burst_den*100.0/256,2801 xr_stat.tx.voip_mtc.burst_dur, "ms",2802 /* gap */2803 indent,2804 xr_stat.tx.voip_mtc.gap_den, xr_stat.tx.voip_mtc.gap_den*100.0/256,2805 xr_stat.tx.voip_mtc.gap_dur, "ms",2806 /* delay */2807 indent,2808 xr_stat.tx.voip_mtc.rnd_trip_delay, "ms",2809 xr_stat.tx.voip_mtc.end_sys_delay, "ms",2810 /* level */2811 indent,2812 signal_lvl, "dB",2813 noise_lvl, "dB",2814 rerl, "",2815 /* quality */2816 indent,2817 r_factor, ext_r_factor,2818 indent,2819 mos_lq, mos_cq,2820 /* config */2821 indent,2822 plc, jba, jbr, xr_stat.tx.voip_mtc.gmin,2823 /* JB delay */2824 indent,2825 xr_stat.tx.voip_mtc.jb_nom, "ms",2826 xr_stat.tx.voip_mtc.jb_max, "ms",2827 xr_stat.tx.voip_mtc.jb_abs_max, "ms"2828 );2829 VALIDATE_PRINT_BUF();2830 2831 2832 /* RTT delay (by receiver side) */2833 len = pj_ansi_snprintf(p, end-p,2834 "%s RTT (from recv) min avg max last dev",2835 indent);2836 VALIDATE_PRINT_BUF();2837 len = pj_ansi_snprintf(p, end-p,2838 "%s RTT msec : %7.3f %7.3f %7.3f %7.3f %7.3f",2839 indent,2840 xr_stat.rtt.min / 1000.0,2841 xr_stat.rtt.mean / 1000.0,2842 xr_stat.rtt.max / 1000.0,2843 xr_stat.rtt.last / 1000.0,2844 pj_math_stat_get_stddev(&xr_stat.rtt) / 1000.02845 );2846 VALIDATE_PRINT_BUF();2847 } while(0);2848 #endif2849 2850 }2851 }2852 2853 2854 /* Print call info */2855 void print_call(const char *title,2856 int call_id,2857 char *buf, pj_size_t size)2858 {2859 int len;2860 pjsip_inv_session *inv = pjsua_var.calls[call_id].inv;2861 pjsip_dialog *dlg = inv->dlg;2862 char userinfo[128];2863 2864 /* Dump invite sesion info. */2865 2866 len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo));2867 if (len < 0)2868 pj_ansi_strcpy(userinfo, "<--uri too long-->");2869 else2870 userinfo[len] = '\0';2871 2872 len = pj_ansi_snprintf(buf, size, "%s[%s] %s",2873 title,2874 pjsip_inv_state_name(inv->state),2875 userinfo);2876 if (len < 1 || len >= (int)size) {2877 pj_ansi_strcpy(buf, "<--uri too long-->");2878 len = 18;2879 } else2880 buf[len] = '\0';2881 }2882 2883 2884 /*2885 * Dump call and media statistics to string.2886 */2887 PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id,2888 pj_bool_t with_media,2889 char *buffer,2890 unsigned maxlen,2891 const char *indent)2892 {2893 pjsua_call *call;2894 pjsip_dialog *dlg;2895 pj_time_val duration, res_delay, con_delay;2896 char tmp[128];2897 char *p, *end;2898 pj_status_t status;2899 int len;2900 pjmedia_transport_info tp_info;2901 2902 PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,2903 PJ_EINVAL);2904 2905 status = acquire_call("pjsua_call_dump()", call_id, &call, &dlg);2906 if (status != PJ_SUCCESS)2907 return status;2908 2909 *buffer = '\0';2910 p = buffer;2911 end = buffer + maxlen;2912 len = 0;2913 2914 print_call(indent, call_id, tmp, sizeof(tmp));2915 2916 len = pj_ansi_strlen(tmp);2917 pj_ansi_strcpy(buffer, tmp);2918 2919 p += len;2920 *p++ = '\r';2921 *p++ = '\n';2922 2923 /* Calculate call duration */2924 if (call->conn_time.sec != 0) {2925 pj_gettimeofday(&duration);2926 PJ_TIME_VAL_SUB(duration, call->conn_time);2927 con_delay = call->conn_time;2928 PJ_TIME_VAL_SUB(con_delay, call->start_time);2929 } else {2930 duration.sec = duration.msec = 0;2931 con_delay.sec = con_delay.msec = 0;2932 }2933 2934 /* Calculate first response delay */2935 if (call->res_time.sec != 0) {2936 res_delay = call->res_time;2937 PJ_TIME_VAL_SUB(res_delay, call->start_time);2938 } else {2939 res_delay.sec = res_delay.msec = 0;2940 }2941 2942 /* Print duration */2943 len = pj_ansi_snprintf(p, end-p,2944 "%s Call time: %02dh:%02dm:%02ds, "2945 "1st res in %d ms, conn in %dms",2946 indent,2947 (int)(duration.sec / 3600),2948 (int)((duration.sec % 3600)/60),2949 (int)(duration.sec % 60),2950 (int)PJ_TIME_VAL_MSEC(res_delay),2951 (int)PJ_TIME_VAL_MSEC(con_delay));2952 2953 if (len > 0 && len < end-p) {2954 p += len;2955 *p++ = '\n';2956 *p = '\0';2957 }2958 2959 /* Get and ICE SRTP status */2960 pjmedia_transport_info_init(&tp_info);2961 pjmedia_transport_get_info(call->med_tp, &tp_info);2962 if (tp_info.specific_info_cnt > 0) {2963 unsigned i;2964 for (i = 0; i < tp_info.specific_info_cnt; ++i) {2965 if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP)2966 {2967 pjmedia_srtp_info *srtp_info =2968 (pjmedia_srtp_info*) tp_info.spc_info[i].buffer;2969 2970 len = pj_ansi_snprintf(p, end-p,2971 "%s SRTP status: %s Crypto-suite: %s",2972 indent,2973 (srtp_info->active?"Active":"Not active"),2974 srtp_info->tx_policy.name.ptr);2975 if (len > 0 && len < end-p) {2976 p += len;2977 *p++ = '\n';2978 *p = '\0';2979 }2980 } else if (tp_info.spc_info[i].type==PJMEDIA_TRANSPORT_TYPE_ICE) {2981 const pjmedia_ice_transport_info *ii;2982 2983 ii = (const pjmedia_ice_transport_info*)2984 tp_info.spc_info[i].buffer;2985 2986 len = pj_ansi_snprintf(p, end-p,2987 "%s ICE role: %s, state: %s, comp_cnt: %u",2988 indent,2989 pj_ice_sess_role_name(ii->role),2990 pj_ice_strans_state_name(ii->sess_state),2991 ii->comp_cnt);2992 if (len > 0 && len < end-p) {2993 p += len;2994 *p++ = '\n';2995 *p = '\0';2996 }2997 }2998 }2999 }3000 3001 /* Dump session statistics */3002 if (with_media && call->session)3003 dump_media_session(indent, p, end-p, call);3004 3005 pjsip_dlg_dec_lock(dlg);3006 3007 return PJ_SUCCESS;3008 }3009 2313 3010 2314 /* Proto */ … … 3076 2380 const pj_str_t STR_UPDATE = {"UPDATE", 6}; 3077 2381 const pjmedia_sdp_session *local_sdp = NULL, *new_sdp; 3078 const pjmedia_sdp_media *ref_m; 3079 pjmedia_sdp_media *m; 3080 unsigned i, codec_cnt = 0; 2382 unsigned i; 3081 2383 pj_bool_t rem_can_update; 2384 pj_bool_t need_lock_codec = PJ_FALSE; 3082 2385 pjsip_tx_data *tdata; 3083 2386 pj_status_t status; … … 3111 2414 return PJMEDIA_SDP_EINVER; 3112 2415 3113 /* Verify if media is deactivated */3114 if (call->media_st == PJSUA_CALL_MEDIA_NONE ||3115 call->media_st == PJSUA_CALL_MEDIA_ERROR ||3116 call->media_dir == PJMEDIA_DIR_NONE)3117 {3118 return PJ_EINVALIDOP;3119 }3120 3121 2416 PJ_LOG(3, (THIS_FILE, "Updating media session to use only one codec..")); 3122 2417 … … 3126 2421 */ 3127 2422 new_sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, local_sdp); 3128 m = new_sdp->media[call->audio_idx]; 3129 ref_m = local_sdp->media[call->audio_idx]; 3130 pj_assert(ref_m->desc.port); 3131 codec_cnt = 0; 3132 i = 0; 3133 while (i < m->desc.fmt_count) { 3134 pjmedia_sdp_attr *a; 3135 pj_str_t *fmt = &m->desc.fmt[i]; 3136 3137 if (is_non_av_fmt(m, fmt) || (++codec_cnt == 1)) { 3138 ++i; 2423 2424 for (i = 0; i < call->med_cnt; ++i) { 2425 unsigned j = 0, codec_cnt = 0; 2426 const pjmedia_sdp_media *ref_m; 2427 pjmedia_sdp_media *m; 2428 pjsua_call_media *call_med = &call->media[i]; 2429 2430 /* Verify if media is deactivated */ 2431 if (call_med->state == PJSUA_CALL_MEDIA_NONE || 2432 call_med->state == PJSUA_CALL_MEDIA_ERROR || 2433 call_med->dir == PJMEDIA_DIR_NONE) 2434 { 3139 2435 continue; 3140 2436 } 3141 2437 3142 /* Remove format */ 3143 a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "rtpmap", fmt); 3144 if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a); 3145 a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "fmtp", fmt); 3146 if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a); 3147 pj_array_erase(m->desc.fmt, sizeof(m->desc.fmt[0]), 3148 m->desc.fmt_count, i); 3149 --m->desc.fmt_count; 2438 ref_m = local_sdp->media[i]; 2439 m = new_sdp->media[i]; 2440 2441 /* Verify that media must be active. */ 2442 pj_assert(ref_m->desc.port); 2443 2444 while (j < m->desc.fmt_count) { 2445 pjmedia_sdp_attr *a; 2446 pj_str_t *fmt = &m->desc.fmt[j]; 2447 2448 if (is_non_av_fmt(m, fmt) || (++codec_cnt == 1)) { 2449 ++j; 2450 continue; 2451 } 2452 2453 /* Remove format */ 2454 a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "rtpmap", fmt); 2455 if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a); 2456 a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "fmtp", fmt); 2457 if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a); 2458 pj_array_erase(m->desc.fmt, sizeof(m->desc.fmt[0]), 2459 m->desc.fmt_count, j); 2460 --m->desc.fmt_count; 2461 } 2462 2463 need_lock_codec |= (ref_m->desc.fmt_count > m->desc.fmt_count); 3150 2464 } 3151 2465 … … 3154 2468 * increase the SDP version (should not happen!). 3155 2469 */ 3156 if ( ref_m->desc.fmt_count == m->desc.fmt_count)2470 if (!need_lock_codec) 3157 2471 return PJ_SUCCESS; 3158 2472 … … 3202 2516 pjsip_inv_session *inv = call->inv; 3203 2517 const pjmedia_sdp_session *local_sdp, *remote_sdp; 3204 const pjmedia_sdp_media *rem_m, *loc_m;3205 unsigned codec_cnt=0, i;3206 2518 pj_time_val delay = {0, 0}; 3207 2519 const pj_str_t st_update = {"UPDATE", 6}; 2520 unsigned i; 2521 pj_bool_t has_mult_fmt = PJ_FALSE; 3208 2522 pj_status_t status; 3209 2523 … … 3217 2531 /* Skip this if we are the answerer */ 3218 2532 if (!inv->neg || !pjmedia_sdp_neg_was_answer_remote(inv->neg)) { 3219 return PJ_SUCCESS;3220 }3221 3222 /* Skip this if the media is inactive or error */3223 if (call->media_st == PJSUA_CALL_MEDIA_NONE ||3224 call->media_st == PJSUA_CALL_MEDIA_ERROR ||3225 call->media_dir == PJMEDIA_DIR_NONE)3226 {3227 2533 return PJ_SUCCESS; 3228 2534 } … … 3246 2552 return status; 3247 2553 3248 PJ_ASSERT_RETURN(call->audio_idx>=0 && 3249 call->audio_idx < (int)remote_sdp->media_count, 3250 PJ_EINVALIDOP); 3251 3252 rem_m = remote_sdp->media[call->audio_idx]; 3253 loc_m = local_sdp->media[call->audio_idx]; 3254 3255 /* Verify that media must be active. */ 3256 pj_assert(loc_m->desc.port && rem_m->desc.port); 3257 3258 /* Count the formats in the answer. */ 3259 if (rem_m->desc.fmt_count==1) { 3260 codec_cnt = 1; 3261 } else { 3262 for (i=0; i<rem_m->desc.fmt_count && codec_cnt <= 1; ++i) { 3263 if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[i])) 3264 ++codec_cnt; 3265 } 3266 } 3267 if (codec_cnt <= 1) { 3268 /* Answer contains single codec. */ 3269 call->lock_codec.retry_cnt = 0; 2554 /* Find multiple codecs answer in all media */ 2555 for (i = 0; i < call->med_cnt; ++i) { 2556 pjsua_call_media *call_med = &call->media[i]; 2557 const pjmedia_sdp_media *rem_m, *loc_m; 2558 unsigned codec_cnt = 0; 2559 2560 /* Skip this if the media is inactive or error */ 2561 if (call_med->state == PJSUA_CALL_MEDIA_NONE || 2562 call_med->state == PJSUA_CALL_MEDIA_ERROR || 2563 call_med->dir == PJMEDIA_DIR_NONE) 2564 { 2565 continue; 2566 } 2567 2568 /* Remote may answer with less media lines. */ 2569 if (i >= remote_sdp->media_count) 2570 continue; 2571 2572 rem_m = remote_sdp->media[i]; 2573 loc_m = local_sdp->media[i]; 2574 2575 /* Verify that media must be active. */ 2576 pj_assert(loc_m->desc.port && rem_m->desc.port); 2577 2578 /* Count the formats in the answer. */ 2579 if (rem_m->desc.fmt_count==1) { 2580 codec_cnt = 1; 2581 } else { 2582 unsigned j; 2583 for (j=0; j<rem_m->desc.fmt_count && codec_cnt <= 1; ++j) { 2584 if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[j])) 2585 ++codec_cnt; 2586 } 2587 } 2588 2589 if (codec_cnt > 1) { 2590 has_mult_fmt = PJ_TRUE; 2591 break; 2592 } 2593 } 2594 2595 /* Each media in the answer already contains single codec. */ 2596 if (!has_mult_fmt) { 2597 call->lock_codec.retry_cnt = 0; 3270 2598 return PJ_SUCCESS; 3271 2599 } … … 3539 2867 3540 2868 /* Add SDP in 488 status */ 3541 if (call && call->med_tp && tdata->msg->type==PJSIP_RESPONSE_MSG && 2869 #if DISABLED_FOR_TICKET_1185 2870 if (call && call->tp && tdata->msg->type==PJSIP_RESPONSE_MSG && 3542 2871 code==PJSIP_SC_NOT_ACCEPTABLE_HERE) 3543 2872 { … … 3554 2883 } 3555 2884 } 2885 #endif 3556 2886 3557 2887 pjsip_inv_send_msg(inv, tdata); … … 3661 2991 pjmedia_sdp_session *sdp) 3662 2992 { 3663 pjmedia_sdp_media *m;2993 unsigned mi; 3664 2994 3665 2995 /* Call-hold is done by set the media direction to 'sendonly' … … 3669 2999 */ 3670 3000 /* http://trac.pjsip.org/repos/ticket/880 3671 if (call-> media_dir != PJMEDIA_DIR_ENCODING) {3001 if (call->dir != PJMEDIA_DIR_ENCODING) { 3672 3002 */ 3673 3003 /* https://trac.pjsip.org/repos/ticket/1142: … … 3675 3005 */ 3676 3006 3677 m = sdp->media[call->audio_idx]; 3678 3679 if (call->call_hold_type == PJSUA_CALL_HOLD_TYPE_RFC2543) { 3680 pjmedia_sdp_conn *conn; 3681 pjmedia_sdp_attr *attr; 3682 3683 /* Get SDP media connection line */ 3684 conn = m->conn; 3685 if (!conn) 3686 conn = sdp->conn; 3687 3688 /* Modify address */ 3689 conn->addr = pj_str("0.0.0.0"); 3690 3691 /* Remove existing directions attributes */ 3692 pjmedia_sdp_media_remove_all_attr(m, "sendrecv"); 3693 pjmedia_sdp_media_remove_all_attr(m, "sendonly"); 3694 pjmedia_sdp_media_remove_all_attr(m, "recvonly"); 3695 pjmedia_sdp_media_remove_all_attr(m, "inactive"); 3696 3697 /* Add inactive attribute */ 3698 attr = pjmedia_sdp_attr_create(pool, "inactive", NULL); 3699 pjmedia_sdp_media_add_attr(m, attr); 3700 3701 3702 } else { 3703 pjmedia_sdp_attr *attr; 3704 3705 /* Remove existing directions attributes */ 3706 pjmedia_sdp_media_remove_all_attr(m, "sendrecv"); 3707 pjmedia_sdp_media_remove_all_attr(m, "sendonly"); 3708 pjmedia_sdp_media_remove_all_attr(m, "recvonly"); 3709 pjmedia_sdp_media_remove_all_attr(m, "inactive"); 3710 3711 if (call->media_dir & PJMEDIA_DIR_ENCODING) { 3712 /* Add sendonly attribute */ 3713 attr = pjmedia_sdp_attr_create(pool, "sendonly", NULL); 3714 pjmedia_sdp_media_add_attr(m, attr); 3715 } else { 3007 for (mi=0; mi<sdp->media_count; ++mi) { 3008 pjmedia_sdp_media *m = sdp->media[mi]; 3009 3010 if (call->call_hold_type == PJSUA_CALL_HOLD_TYPE_RFC2543) { 3011 pjmedia_sdp_conn *conn; 3012 pjmedia_sdp_attr *attr; 3013 3014 /* Get SDP media connection line */ 3015 conn = m->conn; 3016 if (!conn) 3017 conn = sdp->conn; 3018 3019 /* Modify address */ 3020 conn->addr = pj_str("0.0.0.0"); 3021 3022 /* Remove existing directions attributes */ 3023 pjmedia_sdp_media_remove_all_attr(m, "sendrecv"); 3024 pjmedia_sdp_media_remove_all_attr(m, "sendonly"); 3025 pjmedia_sdp_media_remove_all_attr(m, "recvonly"); 3026 pjmedia_sdp_media_remove_all_attr(m, "inactive"); 3027 3716 3028 /* Add inactive attribute */ 3717 3029 attr = pjmedia_sdp_attr_create(pool, "inactive", NULL); 3718 3030 pjmedia_sdp_media_add_attr(m, attr); 3031 3032 3033 } else { 3034 pjmedia_sdp_attr *attr; 3035 3036 /* Remove existing directions attributes */ 3037 pjmedia_sdp_media_remove_all_attr(m, "sendrecv"); 3038 pjmedia_sdp_media_remove_all_attr(m, "sendonly"); 3039 pjmedia_sdp_media_remove_all_attr(m, "recvonly"); 3040 pjmedia_sdp_media_remove_all_attr(m, "inactive"); 3041 3042 if (call->media[mi].dir & PJMEDIA_DIR_ENCODING) { 3043 /* Add sendonly attribute */ 3044 attr = pjmedia_sdp_attr_create(pool, "sendonly", NULL); 3045 pjmedia_sdp_media_add_attr(m, attr); 3046 } else { 3047 /* Add inactive attribute */ 3048 attr = pjmedia_sdp_attr_create(pool, "inactive", NULL); 3049 pjmedia_sdp_media_add_attr(m, attr); 3050 } 3719 3051 } 3720 3052 } … … 3758 3090 { 3759 3091 pjsua_call *call; 3760 pjmedia_sdp_conn *conn = NULL;3761 3092 pjmedia_sdp_session *answer; 3093 unsigned i; 3762 3094 pj_status_t status; 3763 3095 … … 3765 3097 3766 3098 call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id]; 3767 3768 if (call->audio_idx < (int)offer->media_count)3769 conn = offer->media[call->audio_idx]->conn;3770 3771 if (!conn)3772 conn = offer->conn;3773 3099 3774 3100 /* Supply candidate answer */ … … 3785 3111 } 3786 3112 3113 /* Validate media count in the generated answer */ 3114 pj_assert(answer->media_count == offer->media_count); 3115 3787 3116 /* Check if offer's conn address is zero */ 3788 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 || 3789 pj_strcmp2(&conn->addr, "0")==0) 3790 { 3791 /* Modify address */ 3792 answer->conn->addr = pj_str("0.0.0.0"); 3117 for (i = 0; i < answer->media_count; ++i) { 3118 pjmedia_sdp_conn *conn; 3119 3120 conn = offer->media[i]->conn; 3121 if (!conn) 3122 conn = offer->conn; 3123 3124 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 || 3125 pj_strcmp2(&conn->addr, "0")==0) 3126 { 3127 pjmedia_sdp_conn *a_conn = answer->media[i]->conn; 3128 3129 /* Modify answer address */ 3130 if (a_conn) { 3131 a_conn->addr = pj_str("0.0.0.0"); 3132 } else if (answer->conn == NULL || 3133 pj_strcmp2(&answer->conn->addr, "0.0.0.0") != 0) 3134 { 3135 a_conn = PJ_POOL_ZALLOC_T(call->inv->pool_prov, 3136 pjmedia_sdp_conn); 3137 a_conn->net_type = pj_str("IN"); 3138 a_conn->addr_type = pj_str("IP4"); 3139 a_conn->addr = pj_str("0.0.0.0"); 3140 answer->media[i]->conn = a_conn; 3141 } 3142 } 3793 3143 } 3794 3144
Note: See TracChangeset
for help on using the changeset viewer.