- Timestamp:
- Jul 12, 2011 11:08:32 AM (13 years ago)
- Location:
- pjproject/branches/projects/2.0-dev
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/2.0-dev/pjsip-apps/src/pjsua/pjsua_app.c
r3609 r3629 1450 1450 case OPT_VIDEO: 1451 1451 ++cur_acc->max_video_cnt; 1452 cur_acc->vid_in_auto_show = PJ_TRUE; 1453 cur_acc->vid_out_auto_transmit = PJ_TRUE; 1454 PJ_TODO(implement_pjsua_option_for_vid_auto_show_transmit); 1452 1455 break; 1453 1456 case OPT_EXTRA_AUDIO: … … 1457 1460 case OPT_VCAPTURE_DEV: 1458 1461 cfg->vcapture_dev = atoi(pj_optarg); 1462 cur_acc->vid_cap_dev = cfg->vcapture_dev; 1459 1463 break; 1460 1464 1461 1465 case OPT_VRENDER_DEV: 1462 1466 cfg->vrender_dev = atoi(pj_optarg); 1467 cur_acc->vid_rend_dev = cfg->vrender_dev; 1463 1468 break; 1464 1469 -
pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua_internal.h
r3609 r3629 50 50 typedef struct pjsua_call pjsua_call; 51 51 52 52 53 /** 53 54 * Call's media stream. … … 72 73 struct { 73 74 pjmedia_vid_stream *stream; /**< The video stream. */ 74 pjmedia_vid_port *capturer; /**< Video capturer. */ 75 pjmedia_vid_port *renderer; /**< Video renderer. */ 76 pjmedia_converter *conv_enc; /**< Converter for encoding dir.*/ 77 pjmedia_converter *conv_dec; /**< Converter for decoding dir.*/ 75 pjsua_vid_win_id cap_win_id;/**< The video capture window */ 76 pjsua_vid_win_id rdr_win_id;/**< The video render window */ 78 77 } v; 79 78 … … 315 314 pjsua_vid_win_type type; /**< Type. */ 316 315 pj_pool_t *pool; /**< Own pool. */ 317 pjsua_call_id call_id; /**< Owner call or -1*/316 unsigned ref_cnt; /**< Reference counter. */ 318 317 pjmedia_vid_port *vp_cap; /**< Capture vidport. */ 319 318 pjmedia_vid_port *vp_rend; /**< Renderer vidport */ 319 pjmedia_port *tee; /**< Video tee */ 320 320 pjmedia_vid_dev_index preview_cap_id;/* Capture dev id */ 321 321 } pjsua_vid_win; … … 668 668 pj_bzero(w, sizeof(*w)); 669 669 if (pool) pj_pool_reset(pool); 670 w-> call_id = PJSUA_INVALID_ID;670 w->ref_cnt = 0; 671 671 w->pool = pool; 672 672 w->preview_cap_id = PJMEDIA_VID_INVALID_DEV; -
pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_call.c
r3609 r3629 111 111 call_med->ssrc = pj_rand(); 112 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; 113 115 call_med->call = call; 114 116 call_med->idx = i; … … 1317 1319 call_med->strm.a.conf_slot; 1318 1320 } else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 1319 PJ_TODO(vid_fill_in_call_info); 1320 info->media[info->media_cnt].stream.vid.win_in = PJSUA_INVALID_ID; 1321 info->media[info->media_cnt].stream.vid.cap_dev = 1322 PJMEDIA_VID_INVALID_DEV; 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; 1323 1331 } else { 1324 1332 continue; -
pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c
r3609 r3629 1836 1836 1837 1837 1838 void stop_video_stream(pjsua_call_media *call_med); 1839 1838 1840 static void stop_media_session(pjsua_call_id call_id) 1839 1841 { … … 1881 1883 #if PJMEDIA_HAS_VIDEO 1882 1884 else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 1883 pjmedia_vid_stream *strm = call_med->strm.v.stream; 1884 1885 if (strm) { 1886 pjmedia_rtcp_stat stat; 1887 1888 if (call_med->strm.v.capturer) { 1889 pjmedia_vid_port_stop(call_med->strm.v.capturer); 1890 pjmedia_vid_port_destroy(call_med->strm.v.capturer); 1891 call_med->strm.v.capturer = NULL; 1892 } 1893 1894 if (call_med->strm.v.renderer) { 1895 pjmedia_vid_port_stop(call_med->strm.v.renderer); 1896 pjmedia_vid_port_destroy(call_med->strm.v.renderer); 1897 call_med->strm.v.renderer = NULL; 1898 } 1899 1900 if ((call_med->dir & PJMEDIA_DIR_ENCODING) && 1901 (pjmedia_vid_stream_get_stat(strm, &stat) == PJ_SUCCESS)) 1902 { 1903 /* Save RTP timestamp & sequence, so when media session is 1904 * restarted, those values will be restored as the initial 1905 * RTP timestamp & sequence of the new media session. So in 1906 * the same call session, RTP timestamp and sequence are 1907 * guaranteed to be contigue. 1908 */ 1909 call_med->rtp_tx_seq_ts_set = 1 | (1 << 1); 1910 call_med->rtp_tx_seq = stat.rtp_tx_last_seq; 1911 call_med->rtp_tx_ts = stat.rtp_tx_last_ts; 1912 } 1913 1914 pjmedia_vid_stream_destroy(strm); 1915 call_med->strm.v.stream = NULL; 1916 } 1885 stop_video_stream(call_med); 1917 1886 } 1918 1887 #endif … … 2183 2152 2184 2153 2185 #if PJMEDIA_HAS_VIDEO 2186 2187 static pj_status_t video_channel_update(pjsua_call_media *call_med, 2188 pj_pool_t *tmp_pool, 2189 const pjmedia_sdp_session *local_sdp, 2190 const pjmedia_sdp_session *remote_sdp) 2191 { 2192 pjsua_call *call = call_med->call; 2193 pjmedia_vid_stream_info the_si, *si = &the_si; 2194 pjmedia_port *media_port; 2195 unsigned strm_idx = call_med->idx; 2196 pj_status_t status; 2197 2198 status = pjmedia_vid_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt, 2199 local_sdp, remote_sdp, strm_idx); 2200 if (status != PJ_SUCCESS) 2201 return status; 2202 2203 /* Check if no media is active */ 2204 if (si->dir == PJMEDIA_DIR_NONE) { 2205 /* Call media state */ 2206 call_med->state = PJSUA_CALL_MEDIA_NONE; 2207 2208 /* Call media direction */ 2209 call_med->dir = PJMEDIA_DIR_NONE; 2210 2211 } else { 2212 pjmedia_transport_info tp_info; 2213 2214 /* Start/restart media transport */ 2215 status = pjmedia_transport_media_start(call_med->tp, 2216 tmp_pool, local_sdp, 2217 remote_sdp, strm_idx); 2218 if (status != PJ_SUCCESS) 2219 return status; 2220 2221 call_med->tp_st = PJSUA_MED_TP_RUNNING; 2222 2223 /* Get remote SRTP usage policy */ 2224 pjmedia_transport_info_init(&tp_info); 2225 pjmedia_transport_get_info(call_med->tp, &tp_info); 2226 if (tp_info.specific_info_cnt > 0) { 2227 unsigned i; 2228 for (i = 0; i < tp_info.specific_info_cnt; ++i) { 2229 if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP) 2230 { 2231 pjmedia_srtp_info *srtp_info = 2232 (pjmedia_srtp_info*) tp_info.spc_info[i].buffer; 2233 2234 call_med->rem_srtp_use = srtp_info->peer_use; 2235 break; 2236 } 2237 } 2238 } 2239 2240 /* Optionally, application may modify other stream settings here 2241 * (such as jitter buffer parameters, codec ptime, etc.) 2242 */ 2243 si->jb_init = pjsua_var.media_cfg.jb_init; 2244 si->jb_min_pre = pjsua_var.media_cfg.jb_min_pre; 2245 si->jb_max_pre = pjsua_var.media_cfg.jb_max_pre; 2246 si->jb_max = pjsua_var.media_cfg.jb_max; 2247 2248 /* Set SSRC */ 2249 si->ssrc = call_med->ssrc; 2250 2251 /* Set RTP timestamp & sequence, normally these value are intialized 2252 * automatically when stream session created, but for some cases (e.g: 2253 * call reinvite, call update) timestamp and sequence need to be kept 2254 * contigue. 2255 */ 2256 si->rtp_ts = call_med->rtp_tx_ts; 2257 si->rtp_seq = call_med->rtp_tx_seq; 2258 si->rtp_seq_ts_set = call_med->rtp_tx_seq_ts_set; 2259 2260 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 2261 /* Enable/disable stream keep-alive and NAT hole punch. */ 2262 si->use_ka = pjsua_var.acc[call->acc_id].cfg.use_stream_ka; 2263 #endif 2264 2265 /* Try to get shared format ID between the capture device and 2266 * the encoder to avoid format conversion in the capture device. 2267 */ 2268 if (si->dir & PJMEDIA_DIR_ENCODING) { 2269 pjmedia_vid_dev_info dev_info; 2270 pjmedia_vid_codec_info *codec_info = &si->codec_info; 2271 unsigned i, j; 2272 2273 status = pjmedia_vid_dev_get_info(pjsua_var.vcap_dev, &dev_info); 2274 if (status != PJ_SUCCESS) 2275 return status; 2276 2277 /* Find matched format ID */ 2278 for (i = 0; i < codec_info->dec_fmt_id_cnt; ++i) { 2279 for (j = 0; j < dev_info.fmt_cnt; ++j) { 2280 if (codec_info->dec_fmt_id[i] == 2281 (pjmedia_format_id)dev_info.fmt[j].id) 2282 { 2283 /* Apply the matched format ID to the codec */ 2284 si->codec_param->dec_fmt.id = codec_info->dec_fmt_id[i]; 2285 /* Force outer loop to break */ 2286 i = codec_info->dec_fmt_id_cnt; 2287 break; 2288 } 2289 } 2290 } 2291 } 2292 2293 /* Create session based on session info. */ 2294 status = pjmedia_vid_stream_create(pjsua_var.med_endpt, NULL, si, 2295 call_med->tp, NULL, 2296 &call_med->strm.v.stream); 2297 if (status != PJ_SUCCESS) 2298 return status; 2299 2300 /* Start stream */ 2301 status = pjmedia_vid_stream_start(call_med->strm.v.stream); 2302 if (status != PJ_SUCCESS) 2303 return status; 2304 2305 /* Setup decoding direction */ 2306 if (si->dir & PJMEDIA_DIR_DECODING) { 2307 pjmedia_vid_port_param vport_param; 2308 2309 status = pjmedia_vid_stream_get_port(call_med->strm.v.stream, 2310 PJMEDIA_DIR_DECODING, 2311 &media_port); 2312 if (status != PJ_SUCCESS) 2313 return status; 2314 2315 status = pjmedia_vid_dev_default_param( 2316 tmp_pool, pjsua_var.vrdr_dev, 2317 &vport_param.vidparam); 2318 if (status != PJ_SUCCESS) 2319 return status; 2320 2321 pjmedia_format_copy(&vport_param.vidparam.fmt, 2322 &media_port->info.fmt); 2323 2324 vport_param.vidparam.dir = PJMEDIA_DIR_RENDER; 2325 vport_param.active = PJ_TRUE; 2326 2327 /* Create video renderer */ 2328 status = pjmedia_vid_port_create(tmp_pool, &vport_param, 2329 &call_med->strm.v.renderer); 2330 if (status != PJ_SUCCESS) 2331 return status; 2332 2333 /* Connect the video renderer to media_port */ 2334 status = pjmedia_vid_port_connect(call_med->strm.v.renderer, 2335 media_port, PJ_FALSE); 2336 if (status != PJ_SUCCESS) 2337 return status; 2338 2339 /* Start the video renderer */ 2340 status = pjmedia_vid_port_start(call_med->strm.v.renderer); 2341 if (status != PJ_SUCCESS) 2342 return status; 2343 } 2344 2345 /* Setup encoding direction */ 2346 if (si->dir & PJMEDIA_DIR_ENCODING && !call->local_hold) { 2347 pjmedia_vid_port_param vport_param; 2348 2349 status = pjmedia_vid_stream_get_port(call_med->strm.v.stream, 2350 PJMEDIA_DIR_ENCODING, 2351 &media_port); 2352 if (status != PJ_SUCCESS) 2353 return status; 2354 2355 status = pjmedia_vid_dev_default_param( 2356 tmp_pool, pjsua_var.vcap_dev, 2357 &vport_param.vidparam); 2358 if (status != PJ_SUCCESS) 2359 return status; 2360 2361 pjmedia_format_copy(&vport_param.vidparam.fmt, 2362 &media_port->info.fmt); 2363 vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE; 2364 vport_param.active = PJ_TRUE; 2365 2366 /* Create video capturer */ 2367 status = pjmedia_vid_port_create(tmp_pool, &vport_param, 2368 &call_med->strm.v.capturer); 2369 if (status != PJ_SUCCESS) 2370 return status; 2371 2372 /* Connect the video capturer to media_port */ 2373 status = pjmedia_vid_port_connect(call_med->strm.v.capturer, 2374 media_port, PJ_FALSE); 2375 if (status != PJ_SUCCESS) 2376 return status; 2377 2378 /* Start the video capturer */ 2379 status = pjmedia_vid_port_start(call_med->strm.v.capturer); 2380 if (status != PJ_SUCCESS) 2381 return status; 2382 } 2383 2384 /* Call media direction */ 2385 call_med->dir = si->dir; 2386 2387 /* Call media state */ 2388 if (call->local_hold) 2389 call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD; 2390 else if (call_med->dir == PJMEDIA_DIR_DECODING) 2391 call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD; 2392 else 2393 call_med->state = PJSUA_CALL_MEDIA_ACTIVE; 2394 } 2395 2396 /* Print info. */ 2397 { 2398 char info[80]; 2399 int info_len = 0; 2400 int len; 2401 const char *dir; 2402 2403 switch (si->dir) { 2404 case PJMEDIA_DIR_NONE: 2405 dir = "inactive"; 2406 break; 2407 case PJMEDIA_DIR_ENCODING: 2408 dir = "sendonly"; 2409 break; 2410 case PJMEDIA_DIR_DECODING: 2411 dir = "recvonly"; 2412 break; 2413 case PJMEDIA_DIR_ENCODING_DECODING: 2414 dir = "sendrecv"; 2415 break; 2416 default: 2417 dir = "unknown"; 2418 break; 2419 } 2420 len = pj_ansi_sprintf( info+info_len, 2421 ", stream #%d: %.*s (%s)", strm_idx, 2422 (int)si->codec_info.encoding_name.slen, 2423 si->codec_info.encoding_name.ptr, 2424 dir); 2425 if (len > 0) 2426 info_len += len; 2427 PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 2428 } 2429 2430 return PJ_SUCCESS; 2431 } 2432 2433 #endif 2434 2154 pj_status_t video_channel_update(pjsua_call_media *call_med, 2155 pj_pool_t *tmp_pool, 2156 const pjmedia_sdp_session *local_sdp, 2157 const pjmedia_sdp_session *remote_sdp); 2435 2158 2436 2159 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, -
pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_vid.c
r3609 r3629 24 24 #if PJSUA_HAS_VIDEO 25 25 26 static void free_vid_win(pjsua_vid_win_id wid); 27 26 28 /***************************************************************************** 27 29 * pjsua video subsystem. … … 91 93 for (i=0; i<PJSUA_MAX_VID_WINS; ++i) { 92 94 if (pjsua_var.win[i].pool) { 95 free_vid_win(i); 93 96 pj_pool_release(pjsua_var.win[i].pool); 94 97 pjsua_var.win[i].pool = NULL; … … 283 286 284 287 PJSUA_LOCK(); 288 289 /* Get real capture ID, if set to PJMEDIA_VID_DEFAULT_CAPTURE_DEV */ 290 if (id == PJMEDIA_VID_DEFAULT_CAPTURE_DEV) { 291 pjmedia_vid_dev_info info; 292 pjmedia_vid_dev_get_info(id, &info); 293 id = info.id; 294 } 295 285 296 for (i=0; i<PJSUA_MAX_VID_WINS; ++i) { 286 297 pjsua_vid_win *w = &pjsua_var.win[i]; … … 295 306 } 296 307 297 static pjsua_vid_win_id alloc_vid_win(pjsua_vid_win_type type) 308 309 /* Allocate and initialize pjsua video window: 310 * - If the type is preview, video capture, tee, and render 311 * will be instantiated. 312 * - If the type is stream, only renderer will be created. 313 */ 314 static pj_status_t create_vid_win(pjsua_vid_win_type type, 315 const pjmedia_format *fmt, 316 pjmedia_vid_dev_index rend_id, 317 pjmedia_vid_dev_index cap_id, 318 pj_bool_t show, 319 pjsua_vid_win_id *id) 298 320 { 299 321 pjsua_vid_win_id wid = PJSUA_INVALID_ID; 322 pjsua_vid_win *w = NULL; 323 pjmedia_vid_port_param vp_param; 324 pjmedia_format fmt_; 325 pj_status_t status; 300 326 unsigned i; 301 327 328 /* If type is preview, check if it exists already */ 329 if (type == PJSUA_WND_TYPE_PREVIEW) { 330 wid = pjsua_vid_preview_get_win(cap_id); 331 if (wid != PJSUA_INVALID_ID) { 332 /* Yes, it exists */ 333 334 /* Show window if requested */ 335 if (show) { 336 pjmedia_vid_dev_stream *rdr; 337 338 rdr = pjmedia_vid_port_get_stream(pjsua_var.win[wid].vp_rend); 339 pj_assert(rdr); 340 status = pjmedia_vid_dev_stream_set_cap( 341 rdr, 342 PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE, 343 &show); 344 } 345 346 /* Done */ 347 *id = wid; 348 return PJ_SUCCESS; 349 } 350 } 351 352 /* Allocate window */ 302 353 for (i=0; i<PJSUA_MAX_VID_WINS; ++i) { 303 pjsua_vid_win *w = &pjsua_var.win[i];354 w = &pjsua_var.win[i]; 304 355 if (w->type == PJSUA_WND_TYPE_NONE) { 305 356 wid = i; … … 308 359 } 309 360 } 310 311 return wid; 312 } 361 if (i == PJSUA_MAX_VID_WINS) 362 return PJ_ETOOMANY; 363 364 /* Initialize window */ 365 pjmedia_vid_port_param_default(&vp_param); 366 367 if (w->type == PJSUA_WND_TYPE_PREVIEW) { 368 status = pjmedia_vid_dev_default_param(w->pool, cap_id, 369 &vp_param.vidparam); 370 if (status != PJ_SUCCESS) 371 goto on_error; 372 373 /* Normalize capture ID, in case it was set to 374 * PJMEDIA_VID_DEFAULT_CAPTURE_DEV 375 */ 376 cap_id = vp_param.vidparam.cap_id; 377 378 /* Assign preview capture device ID */ 379 w->preview_cap_id = cap_id; 380 381 /* Create capture video port */ 382 vp_param.active = PJ_TRUE; 383 vp_param.vidparam.dir = PJMEDIA_DIR_CAPTURE; 384 if (fmt) 385 vp_param.vidparam.fmt = *fmt; 386 387 status = pjmedia_vid_port_create(w->pool, &vp_param, &w->vp_cap); 388 if (status != PJ_SUCCESS) 389 goto on_error; 390 391 /* Update format info */ 392 fmt_ = vp_param.vidparam.fmt; 393 fmt = &fmt_; 394 395 /* Create video tee */ 396 status = pjmedia_vid_tee_create(w->pool, fmt, 2, &w->tee); 397 if (status != PJ_SUCCESS) 398 goto on_error; 399 } 400 401 /* Create renderer video port */ 402 status = pjmedia_vid_dev_default_param(w->pool, rend_id, 403 &vp_param.vidparam); 404 if (status != PJ_SUCCESS) 405 goto on_error; 406 407 vp_param.active = (w->type == PJSUA_WND_TYPE_STREAM); 408 vp_param.vidparam.dir = PJMEDIA_DIR_RENDER; 409 vp_param.vidparam.fmt = *fmt; 410 vp_param.vidparam.disp_size = fmt->det.vid.size; 411 vp_param.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE; 412 vp_param.vidparam.window_hide = !show; 413 414 status = pjmedia_vid_port_create(w->pool, &vp_param, &w->vp_rend); 415 if (status != PJ_SUCCESS) 416 goto on_error; 417 418 /* For preview window, connect capturer & renderer (via tee) */ 419 if (w->type == PJSUA_WND_TYPE_PREVIEW) { 420 pjmedia_port *rend_port; 421 422 status = pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE); 423 if (status != PJ_SUCCESS) 424 goto on_error; 425 426 rend_port = pjmedia_vid_port_get_passive_port(w->vp_rend); 427 status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, rend_port); 428 if (status != PJ_SUCCESS) 429 goto on_error; 430 } 431 432 /* Done */ 433 *id = wid; 434 435 return PJ_SUCCESS; 436 437 on_error: 438 free_vid_win(wid); 439 return status; 440 } 441 313 442 314 443 static void free_vid_win(pjsua_vid_win_id wid) 315 444 { 316 445 pjsua_vid_win *w = &pjsua_var.win[wid]; 446 317 447 if (w->vp_cap) { 448 pjmedia_vid_port_stop(w->vp_cap); 449 pjmedia_vid_port_disconnect(w->vp_cap); 318 450 pjmedia_vid_port_destroy(w->vp_cap); 319 451 } 320 452 if (w->vp_rend) { 453 pjmedia_vid_port_stop(w->vp_rend); 321 454 pjmedia_vid_port_destroy(w->vp_rend); 322 455 } 456 if (w->tee) { 457 pjmedia_port_destroy(w->tee); 458 } 323 459 pjsua_vid_win_reset(wid); 324 460 } 461 462 463 static void inc_vid_win(pjsua_vid_win_id wid) 464 { 465 pjsua_vid_win *w; 466 467 pj_assert(wid >= 0 && wid < PJSUA_MAX_VID_WINS); 468 469 w = &pjsua_var.win[wid]; 470 pj_assert(w->type != PJSUA_WND_TYPE_NONE); 471 ++w->ref_cnt; 472 } 473 474 static void dec_vid_win(pjsua_vid_win_id wid) 475 { 476 pjsua_vid_win *w; 477 478 pj_assert(wid >= 0 && wid < PJSUA_MAX_VID_WINS); 479 480 w = &pjsua_var.win[wid]; 481 pj_assert(w->type != PJSUA_WND_TYPE_NONE); 482 if (--w->ref_cnt == 0) 483 free_vid_win(wid); 484 } 485 486 487 /* Internal function: update video channel after SDP negotiation */ 488 pj_status_t video_channel_update(pjsua_call_media *call_med, 489 pj_pool_t *tmp_pool, 490 const pjmedia_sdp_session *local_sdp, 491 const pjmedia_sdp_session *remote_sdp) 492 { 493 pjsua_call *call = call_med->call; 494 pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 495 pjmedia_vid_stream_info the_si, *si = &the_si; 496 pjmedia_port *media_port; 497 unsigned strm_idx = call_med->idx; 498 pj_status_t status; 499 500 status = pjmedia_vid_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt, 501 local_sdp, remote_sdp, strm_idx); 502 if (status != PJ_SUCCESS) 503 return status; 504 505 /* Check if no media is active */ 506 if (si->dir == PJMEDIA_DIR_NONE) { 507 /* Call media state */ 508 call_med->state = PJSUA_CALL_MEDIA_NONE; 509 510 /* Call media direction */ 511 call_med->dir = PJMEDIA_DIR_NONE; 512 513 } else { 514 pjmedia_transport_info tp_info; 515 516 /* Start/restart media transport */ 517 status = pjmedia_transport_media_start(call_med->tp, 518 tmp_pool, local_sdp, 519 remote_sdp, strm_idx); 520 if (status != PJ_SUCCESS) 521 return status; 522 523 call_med->tp_st = PJSUA_MED_TP_RUNNING; 524 525 /* Get remote SRTP usage policy */ 526 pjmedia_transport_info_init(&tp_info); 527 pjmedia_transport_get_info(call_med->tp, &tp_info); 528 if (tp_info.specific_info_cnt > 0) { 529 unsigned i; 530 for (i = 0; i < tp_info.specific_info_cnt; ++i) { 531 if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP) 532 { 533 pjmedia_srtp_info *srtp_info = 534 (pjmedia_srtp_info*) tp_info.spc_info[i].buffer; 535 536 call_med->rem_srtp_use = srtp_info->peer_use; 537 break; 538 } 539 } 540 } 541 542 /* Optionally, application may modify other stream settings here 543 * (such as jitter buffer parameters, codec ptime, etc.) 544 */ 545 si->jb_init = pjsua_var.media_cfg.jb_init; 546 si->jb_min_pre = pjsua_var.media_cfg.jb_min_pre; 547 si->jb_max_pre = pjsua_var.media_cfg.jb_max_pre; 548 si->jb_max = pjsua_var.media_cfg.jb_max; 549 550 /* Set SSRC */ 551 si->ssrc = call_med->ssrc; 552 553 /* Set RTP timestamp & sequence, normally these value are intialized 554 * automatically when stream session created, but for some cases (e.g: 555 * call reinvite, call update) timestamp and sequence need to be kept 556 * contigue. 557 */ 558 si->rtp_ts = call_med->rtp_tx_ts; 559 si->rtp_seq = call_med->rtp_tx_seq; 560 si->rtp_seq_ts_set = call_med->rtp_tx_seq_ts_set; 561 562 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 563 /* Enable/disable stream keep-alive and NAT hole punch. */ 564 si->use_ka = pjsua_var.acc[call->acc_id].cfg.use_stream_ka; 565 #endif 566 567 /* Try to get shared format ID between the capture device and 568 * the encoder to avoid format conversion in the capture device. 569 */ 570 if (si->dir & PJMEDIA_DIR_ENCODING) { 571 pjmedia_vid_dev_info dev_info; 572 pjmedia_vid_codec_info *codec_info = &si->codec_info; 573 unsigned i, j; 574 575 status = pjmedia_vid_dev_get_info(acc->cfg.vid_cap_dev, &dev_info); 576 if (status != PJ_SUCCESS) 577 return status; 578 579 /* Find matched format ID */ 580 for (i = 0; i < codec_info->dec_fmt_id_cnt; ++i) { 581 for (j = 0; j < dev_info.fmt_cnt; ++j) { 582 if (codec_info->dec_fmt_id[i] == 583 (pjmedia_format_id)dev_info.fmt[j].id) 584 { 585 /* Apply the matched format ID to the codec */ 586 si->codec_param->dec_fmt.id = 587 codec_info->dec_fmt_id[i]; 588 589 /* Force outer loop to break */ 590 i = codec_info->dec_fmt_id_cnt; 591 break; 592 } 593 } 594 } 595 } 596 597 /* Create session based on session info. */ 598 status = pjmedia_vid_stream_create(pjsua_var.med_endpt, NULL, si, 599 call_med->tp, NULL, 600 &call_med->strm.v.stream); 601 if (status != PJ_SUCCESS) 602 return status; 603 604 /* Start stream */ 605 status = pjmedia_vid_stream_start(call_med->strm.v.stream); 606 if (status != PJ_SUCCESS) 607 return status; 608 609 /* Setup decoding direction */ 610 if (si->dir & PJMEDIA_DIR_DECODING) { 611 pjsua_vid_win_id wid; 612 pjsua_vid_win *w; 613 614 status = pjmedia_vid_stream_get_port(call_med->strm.v.stream, 615 PJMEDIA_DIR_DECODING, 616 &media_port); 617 if (status != PJ_SUCCESS) 618 return status; 619 620 /* Create stream video window */ 621 status = create_vid_win(PJSUA_WND_TYPE_STREAM, 622 &media_port->info.fmt, 623 acc->cfg.vid_rend_dev, 624 PJSUA_INVALID_ID, 625 acc->cfg.vid_in_auto_show, 626 &wid); 627 if (status != PJ_SUCCESS) 628 return status; 629 630 w = &pjsua_var.win[wid]; 631 632 /* Connect renderer to stream */ 633 status = pjmedia_vid_port_connect(w->vp_rend, media_port, 634 PJ_FALSE); 635 if (status != PJ_SUCCESS) 636 return status; 637 638 /* Start renderer */ 639 status = pjmedia_vid_port_start(w->vp_rend); 640 if (status != PJ_SUCCESS) 641 return status; 642 643 /* Done */ 644 inc_vid_win(wid); 645 call_med->strm.v.rdr_win_id = wid; 646 } 647 648 /* Setup encoding direction */ 649 if (si->dir & PJMEDIA_DIR_ENCODING && !call->local_hold && 650 acc->cfg.vid_out_auto_transmit) 651 { 652 pjsua_vid_win *w; 653 pjsua_vid_win_id wid; 654 655 status = pjmedia_vid_stream_get_port(call_med->strm.v.stream, 656 PJMEDIA_DIR_ENCODING, 657 &media_port); 658 if (status != PJ_SUCCESS) 659 return status; 660 661 /* Create preview video window */ 662 status = create_vid_win(PJSUA_WND_TYPE_PREVIEW, 663 &media_port->info.fmt, 664 acc->cfg.vid_rend_dev, 665 acc->cfg.vid_cap_dev, 666 PJ_FALSE, 667 &wid); 668 if (status != PJ_SUCCESS) 669 return status; 670 671 w = &pjsua_var.win[wid]; 672 673 /* Connect stream to capturer (via video window tee) */ 674 status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, media_port); 675 if (status != PJ_SUCCESS) 676 return status; 677 678 /* Start renderer */ 679 status = pjmedia_vid_port_start(w->vp_rend); 680 if (status != PJ_SUCCESS) 681 return status; 682 683 /* Start capturer */ 684 status = pjmedia_vid_port_start(w->vp_cap); 685 if (status != PJ_SUCCESS) 686 return status; 687 688 /* Done */ 689 inc_vid_win(wid); 690 call_med->strm.v.cap_win_id = wid; 691 } 692 693 /* Call media direction */ 694 call_med->dir = si->dir; 695 696 /* Call media state */ 697 if (call->local_hold) 698 call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD; 699 else if (call_med->dir == PJMEDIA_DIR_DECODING) 700 call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD; 701 else 702 call_med->state = PJSUA_CALL_MEDIA_ACTIVE; 703 } 704 705 /* Print info. */ 706 { 707 char info[80]; 708 int info_len = 0; 709 int len; 710 const char *dir; 711 712 switch (si->dir) { 713 case PJMEDIA_DIR_NONE: 714 dir = "inactive"; 715 break; 716 case PJMEDIA_DIR_ENCODING: 717 dir = "sendonly"; 718 break; 719 case PJMEDIA_DIR_DECODING: 720 dir = "recvonly"; 721 break; 722 case PJMEDIA_DIR_ENCODING_DECODING: 723 dir = "sendrecv"; 724 break; 725 default: 726 dir = "unknown"; 727 break; 728 } 729 len = pj_ansi_sprintf( info+info_len, 730 ", stream #%d: %.*s (%s)", strm_idx, 731 (int)si->codec_info.encoding_name.slen, 732 si->codec_info.encoding_name.ptr, 733 dir); 734 if (len > 0) 735 info_len += len; 736 PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 737 } 738 739 return PJ_SUCCESS; 740 } 741 742 743 /* Internal function to stop video stream */ 744 void stop_video_stream(pjsua_call_media *call_med) 745 { 746 pjmedia_vid_stream *strm = call_med->strm.v.stream; 747 pjmedia_rtcp_stat stat; 748 749 pj_assert(call_med->type == PJMEDIA_TYPE_VIDEO); 750 751 if (!strm) 752 return; 753 754 if (call_med->strm.v.cap_win_id != PJSUA_INVALID_ID) { 755 pjmedia_port *media_port; 756 pjsua_vid_win *w = 757 &pjsua_var.win[call_med->strm.v.cap_win_id]; 758 759 pjmedia_vid_stream_get_port(call_med->strm.v.stream, 760 PJMEDIA_DIR_ENCODING, 761 &media_port); 762 pj_assert(media_port); 763 764 pjmedia_vid_port_stop(w->vp_cap); 765 pjmedia_vid_tee_remove_dst_port(w->tee, media_port); 766 pjmedia_vid_port_start(w->vp_cap); 767 768 dec_vid_win(call_med->strm.v.cap_win_id); 769 } 770 771 if (call_med->strm.v.rdr_win_id != PJSUA_INVALID_ID) { 772 dec_vid_win(call_med->strm.v.rdr_win_id); 773 } 774 775 if ((call_med->dir & PJMEDIA_DIR_ENCODING) && 776 (pjmedia_vid_stream_get_stat(strm, &stat) == PJ_SUCCESS)) 777 { 778 /* Save RTP timestamp & sequence, so when media session is 779 * restarted, those values will be restored as the initial 780 * RTP timestamp & sequence of the new media session. So in 781 * the same call session, RTP timestamp and sequence are 782 * guaranteed to be contigue. 783 */ 784 call_med->rtp_tx_seq_ts_set = 1 | (1 << 1); 785 call_med->rtp_tx_seq = stat.rtp_tx_last_seq; 786 call_med->rtp_tx_ts = stat.rtp_tx_last_ts; 787 } 788 789 pjmedia_vid_stream_destroy(strm); 790 call_med->strm.v.stream = NULL; 791 } 792 325 793 326 794 /* … … 330 798 pjsua_vid_preview_param *prm) 331 799 { 332 pjsua_vid_win_id wid = PJSUA_INVALID_ID; 333 pjsua_vid_win *w = NULL; 334 pjmedia_vid_port_param cap_param, rend_param; 335 pjmedia_port *rend_port; 336 const pjmedia_video_format_detail *vfd; 800 pjsua_vid_win_id wid; 801 pjsua_vid_win *w; 802 pjmedia_vid_dev_index rend_id; 337 803 pj_status_t status; 338 804 339 805 PJSUA_LOCK(); 340 806 341 wid = pjsua_vid_preview_get_win(id); 342 if (wid != PJSUA_INVALID_ID) { 343 /* Preview already started for this device */ 344 PJSUA_UNLOCK(); 345 return PJ_SUCCESS; 346 } 347 348 wid = alloc_vid_win(PJSUA_WND_TYPE_PREVIEW); 349 if (wid != PJSUA_INVALID_ID) { 350 pjsua_var.win[wid].preview_cap_id = id; 351 } 352 if (wid == PJSUA_INVALID_ID) { 353 PJSUA_UNLOCK(); 354 return PJ_ETOOMANY; 355 } 807 if (prm) { 808 rend_id = prm->rend_id; 809 } else { 810 rend_id = PJMEDIA_VID_DEFAULT_RENDER_DEV; 811 } 812 813 status = create_vid_win(PJSUA_WND_TYPE_PREVIEW, NULL, rend_id, id, 814 PJ_TRUE, &wid); 815 if (status != PJ_SUCCESS) { 816 PJSUA_UNLOCK(); 817 return status; 818 } 819 356 820 w = &pjsua_var.win[wid]; 357 821 358 /* Create capture video port */ 359 pjmedia_vid_port_param_default(&cap_param); 360 cap_param.active = PJ_TRUE; 361 cap_param.vidparam.dir = PJMEDIA_DIR_CAPTURE; 362 status = pjmedia_vid_dev_default_param(w->pool, id, 363 &cap_param.vidparam); 364 if (status != PJ_SUCCESS) 365 goto on_error; 366 367 status = pjmedia_vid_port_create(w->pool, &cap_param, &w->vp_cap); 368 if (status != PJ_SUCCESS) 369 goto on_error; 370 371 vfd = pjmedia_format_get_video_format_detail(&cap_param.vidparam.fmt, 372 PJ_TRUE); 373 if (vfd == NULL) { 374 status = PJ_ENOTFOUND; 375 goto on_error; 376 } 377 378 /* Create renderer video port */ 379 pjmedia_vid_port_param_default(&rend_param); 380 status = pjmedia_vid_dev_default_param(w->pool, 381 PJMEDIA_VID_DEFAULT_RENDER_DEV, 382 &rend_param.vidparam); 383 if (status != PJ_SUCCESS) 384 goto on_error; 385 386 rend_param.active = PJ_FALSE; 387 rend_param.vidparam.dir = PJMEDIA_DIR_RENDER; 388 rend_param.vidparam.fmt = cap_param.vidparam.fmt; 389 rend_param.vidparam.disp_size = vfd->size; 390 391 status = pjmedia_vid_port_create(w->pool, &rend_param, &w->vp_rend); 392 if (status != PJ_SUCCESS) 393 goto on_error; 394 395 /* Connect capture dev to renderer */ 396 rend_port = pjmedia_vid_port_get_passive_port(w->vp_rend); 397 status = pjmedia_vid_port_connect(w->vp_cap, rend_port, PJ_FALSE); 398 if (status != PJ_SUCCESS) 399 goto on_error; 400 401 /* Start devices */ 822 /* Start capturer */ 402 823 status = pjmedia_vid_port_start(w->vp_rend); 403 if (status != PJ_SUCCESS) 404 goto on_error; 405 824 if (status != PJ_SUCCESS) { 825 PJSUA_UNLOCK(); 826 return status; 827 } 828 829 /* Start renderer */ 406 830 status = pjmedia_vid_port_start(w->vp_cap); 407 if (status != PJ_SUCCESS) 408 goto on_error; 409 410 /* Done */ 831 if (status != PJ_SUCCESS) { 832 PJSUA_UNLOCK(); 833 return status; 834 } 835 836 inc_vid_win(wid); 837 411 838 PJSUA_UNLOCK(); 412 839 return PJ_SUCCESS; 413 414 on_error:415 if (wid != PJSUA_INVALID_ID) {416 free_vid_win(wid);417 }418 419 PJSUA_UNLOCK();420 return status;421 840 } 422 841 … … 427 846 { 428 847 pjsua_vid_win_id wid = PJSUA_INVALID_ID; 429 pjsua_vid_win *w;430 pj_status_t status;431 848 432 849 PJSUA_LOCK(); … … 437 854 } 438 855 439 w = &pjsua_var.win[wid]; 440 441 status = pjmedia_vid_port_stop(w->vp_cap); 442 status = pjmedia_vid_port_stop(w->vp_rend); 443 444 free_vid_win(wid); 856 dec_vid_win(wid); 445 857 446 858 PJSUA_UNLOCK(); … … 461 873 { 462 874 pjsua_vid_win *w; 875 pjmedia_vid_dev_stream *s; 876 pjmedia_vid_param vparam; 877 pj_status_t status; 463 878 464 879 PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS && wi, PJ_EINVAL); … … 471 886 } 472 887 473 PJ_TODO(vid_implement_pjsua_vid_win_get_info); 888 s = pjmedia_vid_port_get_stream(w->vp_rend); 889 if (s == NULL) { 890 PJSUA_UNLOCK(); 891 return PJ_EINVAL; 892 } 893 894 status = pjmedia_vid_dev_stream_get_param(s, &vparam); 895 if (status != PJ_SUCCESS) { 896 PJSUA_UNLOCK(); 897 return status; 898 } 899 900 wi->show = !vparam.window_hide; 901 wi->pos = vparam.window_pos; 902 wi->size = vparam.disp_size; 903 474 904 PJSUA_UNLOCK(); 475 905 476 return PJ_ ENOTSUP;906 return PJ_SUCCESS; 477 907 } 478 908 … … 484 914 { 485 915 pjsua_vid_win *w; 916 pjmedia_vid_dev_stream *s; 917 pj_status_t status; 486 918 487 919 PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS, PJ_EINVAL); … … 494 926 } 495 927 496 PJ_TODO(vid_implement_pjsua_vid_win_set_show); 928 s = pjmedia_vid_port_get_stream(w->vp_rend); 929 if (s == NULL) { 930 PJSUA_UNLOCK(); 931 return PJ_EINVAL; 932 } 933 934 status = pjmedia_vid_dev_stream_set_cap(s, 935 PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE, &show); 936 497 937 PJSUA_UNLOCK(); 498 938 499 return PJ_ENOTSUP;939 return status; 500 940 } 501 941 … … 507 947 { 508 948 pjsua_vid_win *w; 949 pjmedia_vid_dev_stream *s; 950 pj_status_t status; 509 951 510 952 PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS && pos, PJ_EINVAL); … … 517 959 } 518 960 519 PJ_TODO(vid_implement_pjsua_vid_win_set_pos); 961 s = pjmedia_vid_port_get_stream(w->vp_rend); 962 if (s == NULL) { 963 PJSUA_UNLOCK(); 964 return PJ_EINVAL; 965 } 966 967 status = pjmedia_vid_dev_stream_set_cap(s, 968 PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION, &pos); 969 520 970 PJSUA_UNLOCK(); 521 971 522 return PJ_ENOTSUP;972 return status; 523 973 } 524 974 … … 530 980 { 531 981 pjsua_vid_win *w; 982 pjmedia_vid_dev_stream *s; 983 pj_status_t status; 532 984 533 985 PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS && size, PJ_EINVAL); … … 540 992 } 541 993 542 PJ_TODO(vid_implement_pjsua_vid_win_set_size); 994 s = pjmedia_vid_port_get_stream(w->vp_rend); 995 if (s == NULL) { 996 PJSUA_UNLOCK(); 997 return PJ_EINVAL; 998 } 999 1000 status = pjmedia_vid_dev_stream_set_cap(s, 1001 PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE, &size); 1002 543 1003 PJSUA_UNLOCK(); 544 1004 545 return PJ_ENOTSUP;1005 return status; 546 1006 } 547 1007
Note: See TracChangeset
for help on using the changeset viewer.