Changeset 3629 for pjproject


Ignore:
Timestamp:
Jul 12, 2011 11:08:32 AM (13 years ago)
Author:
nanang
Message:

Re #1263:

  • implemented video window management (get/set visibility, pos, resize)
  • integrated video window and video capture preview into call
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  
    14501450        case OPT_VIDEO: 
    14511451            ++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); 
    14521455            break; 
    14531456        case OPT_EXTRA_AUDIO: 
     
    14571460        case OPT_VCAPTURE_DEV: 
    14581461            cfg->vcapture_dev = atoi(pj_optarg); 
     1462            cur_acc->vid_cap_dev = cfg->vcapture_dev; 
    14591463            break; 
    14601464 
    14611465        case OPT_VRENDER_DEV: 
    14621466            cfg->vrender_dev = atoi(pj_optarg); 
     1467            cur_acc->vid_rend_dev = cfg->vrender_dev; 
    14631468            break; 
    14641469 
  • pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua_internal.h

    r3609 r3629  
    5050typedef struct pjsua_call pjsua_call; 
    5151 
     52 
    5253/** 
    5354 * Call's media stream. 
     
    7273        struct { 
    7374            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    */ 
    7877        } v; 
    7978 
     
    315314    pjsua_vid_win_type           type;          /**< Type.              */ 
    316315    pj_pool_t                   *pool;          /**< Own pool.          */ 
    317     pjsua_call_id                call_id;       /**< Owner call or -1   */ 
     316    unsigned                     ref_cnt;       /**< Reference counter. */ 
    318317    pjmedia_vid_port            *vp_cap;        /**< Capture vidport.   */ 
    319318    pjmedia_vid_port            *vp_rend;       /**< Renderer vidport   */ 
     319    pjmedia_port                *tee;           /**< Video tee          */ 
    320320    pjmedia_vid_dev_index        preview_cap_id;/* Capture dev id       */ 
    321321} pjsua_vid_win; 
     
    668668    pj_bzero(w, sizeof(*w)); 
    669669    if (pool) pj_pool_reset(pool); 
    670     w->call_id = PJSUA_INVALID_ID; 
     670    w->ref_cnt = 0; 
    671671    w->pool = pool; 
    672672    w->preview_cap_id = PJMEDIA_VID_INVALID_DEV; 
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_call.c

    r3609 r3629  
    111111        call_med->ssrc = pj_rand(); 
    112112        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; 
    113115        call_med->call = call; 
    114116        call_med->idx = i; 
     
    13171319                                                call_med->strm.a.conf_slot; 
    13181320        } 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; 
    13231331        } else { 
    13241332            continue; 
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c

    r3609 r3629  
    18361836 
    18371837 
     1838void stop_video_stream(pjsua_call_media *call_med); 
     1839 
    18381840static void stop_media_session(pjsua_call_id call_id) 
    18391841{ 
     
    18811883#if PJMEDIA_HAS_VIDEO 
    18821884        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); 
    19171886        } 
    19181887#endif 
     
    21832152 
    21842153 
    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  
     2154pj_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); 
    24352158 
    24362159pj_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  
    2424#if PJSUA_HAS_VIDEO 
    2525 
     26static void free_vid_win(pjsua_vid_win_id wid); 
     27 
    2628/***************************************************************************** 
    2729 * pjsua video subsystem. 
     
    9193    for (i=0; i<PJSUA_MAX_VID_WINS; ++i) { 
    9294        if (pjsua_var.win[i].pool) { 
     95            free_vid_win(i); 
    9396            pj_pool_release(pjsua_var.win[i].pool); 
    9497            pjsua_var.win[i].pool = NULL; 
     
    283286 
    284287    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 
    285296    for (i=0; i<PJSUA_MAX_VID_WINS; ++i) { 
    286297        pjsua_vid_win *w = &pjsua_var.win[i]; 
     
    295306} 
    296307 
    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 */ 
     314static 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) 
    298320{ 
    299321    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; 
    300326    unsigned i; 
    301327 
     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 */ 
    302353    for (i=0; i<PJSUA_MAX_VID_WINS; ++i) { 
    303         pjsua_vid_win *w = &pjsua_var.win[i]; 
     354        w = &pjsua_var.win[i]; 
    304355        if (w->type == PJSUA_WND_TYPE_NONE) { 
    305356            wid = i; 
     
    308359        } 
    309360    } 
    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 
     437on_error: 
     438    free_vid_win(wid); 
     439    return status; 
     440} 
     441 
    313442 
    314443static void free_vid_win(pjsua_vid_win_id wid) 
    315444{ 
    316445    pjsua_vid_win *w = &pjsua_var.win[wid]; 
     446     
    317447    if (w->vp_cap) { 
     448        pjmedia_vid_port_stop(w->vp_cap); 
     449        pjmedia_vid_port_disconnect(w->vp_cap); 
    318450        pjmedia_vid_port_destroy(w->vp_cap); 
    319451    } 
    320452    if (w->vp_rend) { 
     453        pjmedia_vid_port_stop(w->vp_rend); 
    321454        pjmedia_vid_port_destroy(w->vp_rend); 
    322455    } 
     456    if (w->tee) { 
     457        pjmedia_port_destroy(w->tee); 
     458    } 
    323459    pjsua_vid_win_reset(wid); 
    324460} 
     461 
     462 
     463static 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 
     474static 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 */ 
     488pj_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 */ 
     744void 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 
    325793 
    326794/* 
     
    330798                                            pjsua_vid_preview_param *prm) 
    331799{ 
    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; 
    337803    pj_status_t status; 
    338804 
    339805    PJSUA_LOCK(); 
    340806 
    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 
    356820    w = &pjsua_var.win[wid]; 
    357821 
    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 */ 
    402823    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 */ 
    406830    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 
    411838    PJSUA_UNLOCK(); 
    412839    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; 
    421840} 
    422841 
     
    427846{ 
    428847    pjsua_vid_win_id wid = PJSUA_INVALID_ID; 
    429     pjsua_vid_win *w; 
    430     pj_status_t status; 
    431848 
    432849    PJSUA_LOCK(); 
     
    437854    } 
    438855 
    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); 
    445857 
    446858    PJSUA_UNLOCK(); 
     
    461873{ 
    462874    pjsua_vid_win *w; 
     875    pjmedia_vid_dev_stream *s; 
     876    pjmedia_vid_param vparam; 
     877    pj_status_t status; 
    463878 
    464879    PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS && wi, PJ_EINVAL); 
     
    471886    } 
    472887 
    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 
    474904    PJSUA_UNLOCK(); 
    475905 
    476     return PJ_ENOTSUP; 
     906    return PJ_SUCCESS; 
    477907} 
    478908 
     
    484914{ 
    485915    pjsua_vid_win *w; 
     916    pjmedia_vid_dev_stream *s; 
     917    pj_status_t status; 
    486918 
    487919    PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS, PJ_EINVAL); 
     
    494926    } 
    495927 
    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 
    497937    PJSUA_UNLOCK(); 
    498938 
    499     return PJ_ENOTSUP; 
     939    return status; 
    500940} 
    501941 
     
    507947{ 
    508948    pjsua_vid_win *w; 
     949    pjmedia_vid_dev_stream *s; 
     950    pj_status_t status; 
    509951 
    510952    PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS && pos, PJ_EINVAL); 
     
    517959    } 
    518960 
    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 
    520970    PJSUA_UNLOCK(); 
    521971 
    522     return PJ_ENOTSUP; 
     972    return status; 
    523973} 
    524974 
     
    530980{ 
    531981    pjsua_vid_win *w; 
     982    pjmedia_vid_dev_stream *s; 
     983    pj_status_t status; 
    532984 
    533985    PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS && size, PJ_EINVAL); 
     
    540992    } 
    541993 
    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 
    5431003    PJSUA_UNLOCK(); 
    5441004 
    545     return PJ_ENOTSUP; 
     1005    return status; 
    5461006} 
    5471007 
Note: See TracChangeset for help on using the changeset viewer.