Changeset 5939


Ignore:
Timestamp:
Mar 5, 2019 6:23:02 AM (7 months ago)
Author:
nanang
Message:

Re #2181: Initial version of video conference implementation.

Location:
pjproject/trunk
Files:
2 added
18 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/build/Makefile

    r5827 r5939  
    7474                        transport_ice.o transport_loop.o transport_srtp.o transport_udp.o \ 
    7575                        types.o vid_codec.o vid_codec_util.o \ 
    76                         vid_port.o vid_stream.o vid_stream_info.o vid_tee.o \ 
     76                        vid_port.o vid_stream.o vid_stream_info.o vid_conf.o \ 
    7777                        wav_player.o wav_playlist.o wav_writer.o wave.o \ 
    7878                        wsola.o audiodev.o videodev.o 
  • pjproject/trunk/pjmedia/build/pjmedia.vcproj

    r5820 r5939  
    70087008                        </File> 
    70097009                        <File 
     7010                                RelativePath="..\src\pjmedia\vid_conf.c" 
     7011                                > 
     7012                        </File> 
     7013                        <File 
    70107014                                RelativePath="..\src\pjmedia\vid_port.c" 
    70117015                                > 
     
    76977701                        </File> 
    76987702                        <File 
     7703                                RelativePath="..\include\pjmedia\vid_conf.h" 
     7704                                > 
     7705                        </File> 
     7706                        <File 
    76997707                                RelativePath="..\include\pjmedia\vid_port.h" 
    77007708                                > 
  • pjproject/trunk/pjmedia/include/pjmedia.h

    r3664 r5939  
    6969#include <pjmedia/transport_srtp.h> 
    7070#include <pjmedia/transport_udp.h> 
     71#include <pjmedia/vid_codec.h> 
     72#include <pjmedia/vid_conf.h> 
    7173#include <pjmedia/vid_port.h> 
    72 #include <pjmedia/vid_codec.h> 
    7374#include <pjmedia/vid_stream.h> 
    74 #include <pjmedia/vid_tee.h> 
     75//#include <pjmedia/vid_tee.h> 
    7576#include <pjmedia/wav_playlist.h> 
    7677#include <pjmedia/wav_port.h> 
  • pjproject/trunk/pjmedia/include/pjmedia/converter.h

    r3664 r5939  
    124124 
    125125/** 
     126 * Settings for pjmedia_converter_convert2(). 
     127 */ 
     128typedef void pjmedia_converter_convert_setting; 
     129 
     130 
     131/** 
    126132 * Converter factory operation. 
    127133 */ 
     
    158164{ 
    159165    /** 
    160      * Convert the buffer in the source frame and save the result in the 
     166     * Convert the buffer of the source frame and save the result in the 
    161167     * buffer of the destination frame, according to conversion format that 
    162168     * was specified when the converter was created. 
     
    165171     * of calling this function directly. 
    166172     * 
    167      * @param cv        The converter instance. 
    168      * @param src_frame The source frame. 
    169      * @param dst_frame The destination frame. 
    170      * 
    171      * @return          PJ_SUCCESS if conversion has been performed 
    172      *                  successfully. 
     173     * @param cv                The converter instance. 
     174     * @param src_frame         The source frame. 
     175     * @param dst_frame         The destination frame. 
     176     * 
     177     * @return                  PJ_SUCCESS if conversion has been performed 
     178     *                          successfully. 
    173179     */ 
    174180    pj_status_t (*convert)(pjmedia_converter *cv, 
     
    182188     * of calling this function directly. 
    183189     * 
    184      * @param cv        The converter. 
     190     * @param cv                The converter. 
    185191     */ 
    186192    void (*destroy)(pjmedia_converter *cv); 
     193 
     194    /** 
     195     * Convert a region in the buffer of the source frame and put the result 
     196     * into a region in the buffer of the destination frame, according to 
     197     * conversion format that was specified when the converter was created. 
     198     * 
     199     * Note that application should use #pjmedia_converter_convert2() instead 
     200     * of calling this function directly. 
     201     * 
     202     * @param cv                The converter instance. 
     203     * @param src_frame         The source frame. 
     204     * @param src_frame_size    The source frame size. 
     205     * @param src_reg_pos       The source region position. 
     206     * @param dst_frame         The destination frame. 
     207     * @param dst_frame_size    The destination frame size. 
     208     * @param dst_reg_pos       The destination region position. 
     209     * @param param             This is unused for now and must be NULL. 
     210     * 
     211     * @return                  PJ_SUCCESS if conversion has been performed 
     212     *                          successfully. 
     213     */ 
     214    pj_status_t (*convert2)(pjmedia_converter       *cv, 
     215                            pjmedia_frame           *src_frame, 
     216                            const pjmedia_rect_size *src_frame_size, 
     217                            const pjmedia_coord     *src_pos, 
     218                            pjmedia_frame           *dst_frame, 
     219                            const pjmedia_rect_size *dst_frame_size, 
     220                            const pjmedia_coord     *dst_pos, 
     221                            pjmedia_converter_convert_setting 
     222                                                    *param); 
    187223 
    188224}; 
     
    303339                                               pjmedia_frame *dst_frame); 
    304340 
     341 
     342/** 
     343 * Convert a region in the buffer of the source frame and put the result 
     344 * into a region in the buffer of the destination frame, according to 
     345 * conversion format that was specified when the converter was created. 
     346 * 
     347 * @param cv                The converter instance. 
     348 * @param src_frame         The source frame. 
     349 * @param src_frame_size    The source frame size. 
     350 * @param src_reg_pos       The source region position. 
     351 * @param dst_frame         The destination frame. 
     352 * @param dst_frame_size    The destination frame size. 
     353 * @param dst_reg_pos       The destination region position. 
     354 * @param param             This is unused for now and must be NULL. 
     355 * 
     356 * @return                  PJ_SUCCESS if conversion has been performed 
     357 *                          successfully. 
     358 */ 
     359PJ_DECL(pj_status_t) pjmedia_converter_convert2( 
     360                                    pjmedia_converter       *cv, 
     361                                    pjmedia_frame           *src_frame, 
     362                                    const pjmedia_rect_size *src_frame_size, 
     363                                    const pjmedia_coord     *src_pos, 
     364                                    pjmedia_frame           *dst_frame, 
     365                                    const pjmedia_rect_size *dst_frame_size, 
     366                                    const pjmedia_coord     *dst_pos, 
     367                                    pjmedia_converter_convert_setting 
     368                                                            *param); 
     369 
    305370/** 
    306371 * Destroy the converter. 
  • pjproject/trunk/pjmedia/include/pjmedia/signatures.h

    r3664 r5939  
    198198#define PJMEDIA_SIG_IS_CLASS_VID_OTHER(s) ((s)>>24=='V' && (s)>>16=='O') 
    199199 
     200#define PJMEDIA_SIG_VID_CONF            PJMEDIA_SIG_CLASS_VID_OTHER('C','F') 
    200201#define PJMEDIA_SIG_VID_PORT            PJMEDIA_SIG_CLASS_VID_OTHER('P','O') 
    201202 
  • pjproject/trunk/pjmedia/include/pjmedia/vid_port.h

    r4168 r5939  
    154154 
    155155/** 
     156 * Subscribe media event notifications from the specified media port. 
     157 * Sample use case is that renderer video port needs to monitor stream port 
     158 * events so renderer can adjust its param whenever stream port detects 
     159 * format change. 
     160 * 
     161 * @param vid_port      The video port. 
     162 * @param port          The media port whose events to be monitored. 
     163 * 
     164 * @return              PJ_SUCCESS on success or the appropriate error code. 
     165 */ 
     166PJ_DECL(pj_status_t) pjmedia_vid_port_subscribe_event( 
     167                                                pjmedia_vid_port *vid_port, 
     168                                                pjmedia_port *port); 
     169 
     170/** 
    156171 * Connect the video port to a downstream (slave) media port. This operation 
    157172 * is only valid for video ports created with active interface selected. 
  • pjproject/trunk/pjmedia/src/pjmedia/converter.c

    r5378 r5939  
    192192} 
    193193 
    194  
     194PJ_DEF(pj_status_t) pjmedia_converter_convert2( 
     195                                    pjmedia_converter       *cv, 
     196                                    pjmedia_frame           *src_frame, 
     197                                    const pjmedia_rect_size *src_frame_size, 
     198                                    const pjmedia_coord     *src_pos, 
     199                                    pjmedia_frame           *dst_frame, 
     200                                    const pjmedia_rect_size *dst_frame_size, 
     201                                    const pjmedia_coord     *dst_pos, 
     202                                    void                    *param) 
     203{ 
     204    if (!cv->op->convert2) 
     205        return PJ_ENOTSUP; 
     206 
     207    return (*cv->op->convert2)(cv, src_frame, src_frame_size, src_pos, 
     208                               dst_frame, dst_frame_size, dst_pos, param); 
     209} 
     210 
  • pjproject/trunk/pjmedia/src/pjmedia/converter_libswscale.c

    r5306 r5939  
    3434                                           pjmedia_frame *src_frame, 
    3535                                           pjmedia_frame *dst_frame); 
     36static pj_status_t libswscale_conv_convert2( 
     37                                    pjmedia_converter       *converter, 
     38                                    pjmedia_frame           *src_frame, 
     39                                    const pjmedia_rect_size *src_frame_size, 
     40                                    const pjmedia_coord     *src_pos, 
     41                                    pjmedia_frame           *dst_frame, 
     42                                    const pjmedia_rect_size *dst_frame_size, 
     43                                    const pjmedia_coord     *dst_pos, 
     44                                    pjmedia_converter_convert_setting 
     45                                                            *param); 
    3646static void libswscale_conv_destroy(pjmedia_converter *converter); 
    3747 
     
    6070{ 
    6171    &libswscale_conv_convert, 
    62     &libswscale_conv_destroy 
     72    &libswscale_conv_destroy, 
     73    &libswscale_conv_convert2 
    6374}; 
    6475 
     
    165176} 
    166177 
     178static pj_status_t libswscale_conv_convert2( 
     179                                    pjmedia_converter       *converter, 
     180                                    pjmedia_frame           *src_frame, 
     181                                    const pjmedia_rect_size *src_frame_size, 
     182                                    const pjmedia_coord     *src_pos, 
     183                                    pjmedia_frame           *dst_frame, 
     184                                    const pjmedia_rect_size *dst_frame_size, 
     185                                    const pjmedia_coord     *dst_pos, 
     186                                    pjmedia_converter_convert_setting 
     187                                                            *param) 
     188{ 
     189    struct ffmpeg_converter *fcv = (struct ffmpeg_converter*)converter; 
     190    struct fmt_info *src = &fcv->src, 
     191                    *dst = &fcv->dst; 
     192    int h; 
     193    unsigned j; 
     194    pjmedia_rect_size orig_src_size; 
     195    pjmedia_rect_size orig_dst_size; 
     196 
     197    PJ_UNUSED_ARG(param); 
     198 
     199    /* Save original conversion sizes */ 
     200    orig_src_size = src->apply_param.size; 
     201    orig_dst_size = dst->apply_param.size; 
     202 
     203    /* Set the first act buffer from src frame, and overwrite size. */ 
     204    src->apply_param.buffer = src_frame->buf; 
     205    src->apply_param.size   = *src_frame_size; 
     206    (*src->fmt_info->apply_fmt)(src->fmt_info, &src->apply_param); 
     207 
     208    /* Set the last act buffer from dst frame, and overwrite size. */ 
     209    dst->apply_param.buffer = dst_frame->buf; 
     210    dst->apply_param.size   = *dst_frame_size; 
     211    (*dst->fmt_info->apply_fmt)(dst->fmt_info, &dst->apply_param); 
     212 
     213    for (j = 0; j < src->fmt_info->plane_cnt; ++j) { 
     214        pjmedia_video_apply_fmt_param *ap = &src->apply_param; 
     215        int y = src_pos->y * ap->plane_bytes[j] / ap->strides[j] / 
     216                ap->size.h; 
     217        ap->planes[j] += y * ap->strides[j] + 
     218                         src_pos->x * ap->strides[j] / ap->size.w; 
     219    } 
     220 
     221    for (j = 0; j < dst->fmt_info->plane_cnt; ++j) { 
     222        pjmedia_video_apply_fmt_param *ap = &dst->apply_param; 
     223        int y = dst_pos->y * ap->plane_bytes[j] / ap->strides[j] / 
     224                ap->size.h; 
     225        ap->planes[j] += y * ap->strides[j] + 
     226                         dst_pos->x * ap->strides[j] / ap->size.w; 
     227    } 
     228 
     229    /* Return back the original conversion size */ 
     230    src->apply_param.size = orig_src_size; 
     231    dst->apply_param.size = orig_dst_size; 
     232 
     233    h = sws_scale(fcv->sws_ctx, 
     234                  (const uint8_t* const *)src->apply_param.planes, 
     235                  src->apply_param.strides, 
     236                  0, src->apply_param.size.h, 
     237                  dst->apply_param.planes, dst->apply_param.strides); 
     238 
     239    //sws_scale() return value can't be trusted? There are cases when 
     240    //sws_scale() returns zero but conversion seems to work okay. 
     241    //return h==(int)dst->apply_param.size.h ? PJ_SUCCESS : PJ_EUNKNOWN; 
     242    PJ_UNUSED_ARG(h); 
     243 
     244    return PJ_SUCCESS; 
     245} 
     246 
    167247static void libswscale_conv_destroy(pjmedia_converter *converter) 
    168248{ 
  • pjproject/trunk/pjmedia/src/pjmedia/converter_libyuv.c

    r5378 r5939  
    3737                                       pjmedia_frame *dst_frame); 
    3838 
     39static pj_status_t libyuv_conv_convert2( 
     40                                    pjmedia_converter       *converter, 
     41                                    pjmedia_frame           *src_frame, 
     42                                    const pjmedia_rect_size *src_frame_size, 
     43                                    const pjmedia_coord     *src_pos, 
     44                                    pjmedia_frame           *dst_frame, 
     45                                    const pjmedia_rect_size *dst_frame_size, 
     46                                    const pjmedia_coord     *dst_pos, 
     47                                    void                    *param); 
     48 
    3949static void libyuv_conv_destroy(pjmedia_converter *converter); 
    4050 
     
    4858{ 
    4959    &libyuv_conv_convert, 
    50     &libyuv_conv_destroy 
     60    &libyuv_conv_destroy, 
     61    &libyuv_conv_convert2 
    5162}; 
    5263 
     
    347358 
    348359    /* Convert to I420 or BGRA if needed. */ 
    349     if ((src_id != PJMEDIA_FORMAT_I420) || (src_id != PJMEDIA_FORMAT_BGRA)) { 
     360    if ((src_id != PJMEDIA_FORMAT_I420) && (src_id != PJMEDIA_FORMAT_BGRA)) { 
    350361        pj_uint32_t next_id = get_next_conv_fmt(src_id); 
    351362        if (get_converter_map(src_id, next_id, src_size, dst_size, ++act_num,  
     
    359370 
    360371    /* Scale if needed */ 
    361     need_scale = ((src_size->w != dst_size->w) || 
    362                   (src_size->h != dst_size->h)); 
     372    //need_scale = ((src_size->w != dst_size->w) || 
     373                  //(src_size->h != dst_size->h)); 
     374 
     375    // Always enable scale, as this can be used for rendering a region of 
     376    // a frame to another region of similar/another frame. 
     377    need_scale = PJ_TRUE; 
    363378 
    364379    if (need_scale) { 
     
    623638} 
    624639 
     640static pj_status_t libyuv_conv_convert2( 
     641                                    pjmedia_converter       *converter, 
     642                                    pjmedia_frame           *src_frame, 
     643                                    const pjmedia_rect_size *src_frame_size, 
     644                                    const pjmedia_coord     *src_pos, 
     645                                    pjmedia_frame           *dst_frame, 
     646                                    const pjmedia_rect_size *dst_frame_size, 
     647                                    const pjmedia_coord     *dst_pos, 
     648                                    pjmedia_converter_convert_setting 
     649                                                            *param) 
     650{ 
     651    struct libyuv_converter *lconv = (struct libyuv_converter*)converter; 
     652    int i = 0; 
     653    fmt_info *src_info = &lconv->act[0].src_fmt_info; 
     654    fmt_info *dst_info = &lconv->act[lconv->act_num-1].dst_fmt_info; 
     655    pjmedia_rect_size orig_src_size; 
     656    pjmedia_rect_size orig_dst_size; 
     657 
     658    PJ_UNUSED_ARG(param); 
     659 
     660    /* Save original conversion sizes */ 
     661    orig_src_size = src_info->apply_param.size; 
     662    orig_dst_size = dst_info->apply_param.size; 
     663 
     664    /* Set the first act buffer from src frame, and overwrite size. */ 
     665    src_info->apply_param.buffer = src_frame->buf; 
     666    src_info->apply_param.size   = *src_frame_size; 
     667 
     668    /* Set the last act buffer from dst frame, and overwrite size. */ 
     669    dst_info->apply_param.buffer = dst_frame->buf; 
     670    dst_info->apply_param.size   = *dst_frame_size; 
     671 
     672    for (i=0;i<lconv->act_num;++i) { 
     673        /* Use destination info as the source info for the next act. */ 
     674        struct fmt_info *src_fmt_info = (i==0)? src_info :  
     675                                        &lconv->act[i-1].dst_fmt_info; 
     676 
     677        struct fmt_info *dst_fmt_info = &lconv->act[i].dst_fmt_info;     
     678         
     679        (*src_fmt_info->vid_fmt_info->apply_fmt)(src_fmt_info->vid_fmt_info,  
     680                                                 &src_fmt_info->apply_param); 
     681 
     682        (*dst_fmt_info->vid_fmt_info->apply_fmt)(dst_fmt_info->vid_fmt_info,  
     683                                                 &dst_fmt_info->apply_param); 
     684 
     685        /* For first and last acts, apply plane buffer offset and return back 
     686         * the original sizes. 
     687         */ 
     688        if (i == 0) { 
     689            pjmedia_video_apply_fmt_param *ap = &src_fmt_info->apply_param; 
     690            unsigned j; 
     691            for (j = 0; j < src_fmt_info->vid_fmt_info->plane_cnt; ++j) { 
     692                int y = src_pos->y * ap->plane_bytes[j] / ap->strides[j] / 
     693                        ap->size.h; 
     694                ap->planes[j] += y * ap->strides[j] + src_pos->x * 
     695                                 ap->strides[j] / ap->size.w; 
     696            } 
     697            ap->size = orig_src_size; 
     698        } 
     699        if (i == lconv->act_num-1) { 
     700            pjmedia_video_apply_fmt_param *ap = &dst_fmt_info->apply_param; 
     701            unsigned j; 
     702            for (j = 0; j < dst_fmt_info->vid_fmt_info->plane_cnt; ++j) 
     703            { 
     704                int y = dst_pos->y * ap->plane_bytes[j] / ap->strides[j] / 
     705                        ap->size.h; 
     706                ap->planes[j] += y * ap->strides[j] + dst_pos->x * 
     707                                 ap->strides[j] / ap->size.w; 
     708            } 
     709            ap->size = orig_dst_size; 
     710        } 
     711 
     712        switch (lconv->act[i].act_type) { 
     713        case CONV_PACK_TO_PACK: 
     714            (*lconv->act[i].method.conv_pack_to_pack)( 
     715                              (const uint8*)src_fmt_info->apply_param.planes[0], 
     716                              src_fmt_info->apply_param.strides[0], 
     717                              dst_fmt_info->apply_param.planes[0],  
     718                              dst_fmt_info->apply_param.strides[0], 
     719                              dst_fmt_info->apply_param.size.w,  
     720                              dst_fmt_info->apply_param.size.h); 
     721            break; 
     722        case CONV_PACK_TO_PLANAR: 
     723            (*lconv->act[i].method.conv_pack_to_planar)( 
     724                              (const uint8*)src_fmt_info->apply_param.planes[0], 
     725                              src_fmt_info->apply_param.strides[0], 
     726                              dst_fmt_info->apply_param.planes[0],  
     727                              dst_fmt_info->apply_param.strides[0], 
     728                              dst_fmt_info->apply_param.planes[1],  
     729                              dst_fmt_info->apply_param.strides[1], 
     730                              dst_fmt_info->apply_param.planes[2],  
     731                              dst_fmt_info->apply_param.strides[2], 
     732                              dst_fmt_info->apply_param.size.w,  
     733                              dst_fmt_info->apply_param.size.h); 
     734            break; 
     735        case CONV_PLANAR_TO_PACK: 
     736            (*lconv->act[i].method.conv_planar_to_pack)( 
     737                              (const uint8*)src_fmt_info->apply_param.planes[0], 
     738                              src_fmt_info->apply_param.strides[0], 
     739                              (const uint8*)src_fmt_info->apply_param.planes[1], 
     740                              src_fmt_info->apply_param.strides[1], 
     741                              (const uint8*)src_fmt_info->apply_param.planes[2], 
     742                              src_fmt_info->apply_param.strides[2], 
     743                              dst_fmt_info->apply_param.planes[0],  
     744                              dst_fmt_info->apply_param.strides[0], 
     745                              dst_fmt_info->apply_param.size.w,  
     746                              dst_fmt_info->apply_param.size.h); 
     747            break; 
     748        case CONV_PLANAR_TO_PLANAR: 
     749            (*lconv->act[i].method.conv_planar_to_planar)( 
     750                              (const uint8*)src_fmt_info->apply_param.planes[0], 
     751                              src_fmt_info->apply_param.strides[0], 
     752                              (const uint8*)src_fmt_info->apply_param.planes[1], 
     753                              src_fmt_info->apply_param.strides[1], 
     754                              (const uint8*)src_fmt_info->apply_param.planes[2], 
     755                              src_fmt_info->apply_param.strides[2], 
     756                              dst_fmt_info->apply_param.planes[0],  
     757                              dst_fmt_info->apply_param.strides[0], 
     758                              dst_fmt_info->apply_param.planes[1],  
     759                              dst_fmt_info->apply_param.strides[1], 
     760                              dst_fmt_info->apply_param.planes[2],  
     761                              dst_fmt_info->apply_param.strides[2], 
     762                              dst_fmt_info->apply_param.size.w,  
     763                              dst_fmt_info->apply_param.size.h); 
     764            break; 
     765        case SCALE_PACK: 
     766            (*lconv->act[i].method.scale_pack)( 
     767                              (const uint8*)src_fmt_info->apply_param.planes[0], 
     768                              src_fmt_info->apply_param.strides[0], 
     769                              src_fmt_info->apply_param.size.w, 
     770                              src_fmt_info->apply_param.size.h, 
     771                              (uint8*)dst_fmt_info->apply_param.planes[0], 
     772                              dst_fmt_info->apply_param.strides[0], 
     773                              dst_fmt_info->apply_param.size.w, 
     774                              dst_fmt_info->apply_param.size.h, 
     775                              LIBYUV_FILTER_MODE); 
     776            break;       
     777        case SCALE_PLANAR: 
     778            (*lconv->act[i].method.scale_planar)( 
     779                              (const uint8*)src_fmt_info->apply_param.planes[0], 
     780                              src_fmt_info->apply_param.strides[0], 
     781                              (const uint8*)src_fmt_info->apply_param.planes[1], 
     782                              src_fmt_info->apply_param.strides[1], 
     783                              (const uint8*)src_fmt_info->apply_param.planes[2], 
     784                              src_fmt_info->apply_param.strides[2], 
     785                              src_fmt_info->apply_param.size.w, 
     786                              src_fmt_info->apply_param.size.h, 
     787                              (uint8*)dst_fmt_info->apply_param.planes[0], 
     788                              dst_fmt_info->apply_param.strides[0], 
     789                              (uint8*)dst_fmt_info->apply_param.planes[1], 
     790                              dst_fmt_info->apply_param.strides[1], 
     791                              (uint8*)dst_fmt_info->apply_param.planes[2], 
     792                              dst_fmt_info->apply_param.strides[2], 
     793                              dst_fmt_info->apply_param.size.w, 
     794                              dst_fmt_info->apply_param.size.h, 
     795                              LIBYUV_FILTER_MODE); 
     796            break;       
     797        };       
     798    }     
     799    return PJ_SUCCESS; 
     800} 
     801 
    625802static void libyuv_conv_destroy(pjmedia_converter *converter) 
    626803{ 
  • pjproject/trunk/pjmedia/src/pjmedia/vid_port.c

    r5868 r5939  
    647647        vp->pasv_port = pp = PJ_POOL_ZALLOC_T(pool, vid_pasv_port); 
    648648        pp->vp = vp; 
    649         pp->base.get_frame = &vid_pasv_port_get_frame; 
    650         pp->base.put_frame = &vid_pasv_port_put_frame; 
     649        if (prm->vidparam.dir & PJMEDIA_DIR_CAPTURE) 
     650            pp->base.get_frame = &vid_pasv_port_get_frame; 
     651        if (prm->vidparam.dir & PJMEDIA_DIR_RENDER) 
     652            pp->base.put_frame = &vid_pasv_port_put_frame; 
    651653        pjmedia_port_info_init2(&pp->base.info, &vp->dev_name, 
    652654                                PJMEDIA_SIG_VID_PORT, 
     
    730732} 
    731733 
     734 
     735PJ_DEF(pj_status_t) pjmedia_vid_port_subscribe_event( 
     736                                                pjmedia_vid_port *vp, 
     737                                                pjmedia_port *port) 
     738{ 
     739    PJ_ASSERT_RETURN(vp && port, PJ_EINVAL); 
     740 
     741    /* Subscribe to port's events */ 
     742    return pjmedia_event_subscribe(NULL, &client_port_event_cb, vp, port); 
     743} 
    732744 
    733745PJ_DEF(pj_status_t) pjmedia_vid_port_connect(pjmedia_vid_port *vp, 
     
    10011013        } 
    10021014         
    1003         if (vp->stream_role == ROLE_PASSIVE) { 
     1015        if (vp->role == ROLE_ACTIVE && vp->stream_role == ROLE_PASSIVE) { 
    10041016            pjmedia_clock_param clock_param; 
    10051017             
     
    10171029        /* pjmedia_vid_port_start(vp); */ 
    10181030        pjmedia_vid_dev_stream_start(vp->strm); 
     1031 
     1032        /* Update passive port info from the video stream */ 
     1033        if (vp->role == ROLE_PASSIVE) { 
     1034            pjmedia_format_copy(&vp->pasv_port->base.info.fmt, 
     1035                                &event->data.fmt_changed.new_fmt); 
     1036        } 
    10191037    } 
    10201038     
  • pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c

    r5913 r5939  
    929929    rtp_ts_len = stream->frame_ts_len; 
    930930 
     931    /* Empty video frame? Just update RTP timestamp for now */ 
     932    if (frame->type==PJMEDIA_FRAME_TYPE_VIDEO && frame->size==0) { 
     933        pjmedia_rtp_encode_rtp(&channel->rtp, channel->pt, 1, 0, 
     934                               rtp_ts_len,  (const void**)&rtphdr, 
     935                               &rtphdrlen); 
     936        return PJ_SUCCESS; 
     937    } 
     938 
    931939    /* Init frame_out buffer. */ 
    932940    pj_bzero(&frame_out, sizeof(frame_out)); 
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_cli.c

    r5659 r5939  
    103103#define CMD_VIDEO_CODEC             ((CMD_VIDEO*10)+6) 
    104104#define CMD_VIDEO_WIN               ((CMD_VIDEO*10)+7) 
     105#define CMD_VIDEO_CONF              ((CMD_VIDEO*10)+8) 
    105106 
    106107/* video level 3 command */ 
     
    130131#define CMD_VIDEO_WIN_MOVE          ((CMD_VIDEO_WIN*10)+5) 
    131132#define CMD_VIDEO_WIN_RESIZE        ((CMD_VIDEO_WIN*10)+6) 
     133#define CMD_VIDEO_CONF_LIST         ((CMD_VIDEO_CONF*10)+1) 
     134#define CMD_VIDEO_CONF_CONNECT      ((CMD_VIDEO_CONF*10)+2) 
     135#define CMD_VIDEO_CONF_DISCONNECT   ((CMD_VIDEO_CONF*10)+3) 
    132136 
    133137/* dynamic choice argument list */ 
     
    24662470} 
    24672471 
     2472static pj_status_t cmd_vid_conf_list() 
     2473{ 
     2474    pjsua_conf_port_id id[100]; 
     2475    unsigned count = PJ_ARRAY_SIZE(id); 
     2476    unsigned i; 
     2477    pj_status_t status; 
     2478 
     2479    status = pjsua_vid_conf_enum_ports(id, &count); 
     2480    if (status != PJ_SUCCESS) { 
     2481        PJ_PERROR(1,(THIS_FILE, status, 
     2482                     "Failed enumerating video conf bridge ports")); 
     2483        return status; 
     2484    } 
     2485 
     2486    PJ_LOG(3,(THIS_FILE," Video conference has %d ports:\n", count)); 
     2487    PJ_LOG(3,(THIS_FILE," id name                   format               rx           tx    \n")); 
     2488    PJ_LOG(3,(THIS_FILE," ------------------------------------------------------------------\n")); 
     2489    for (i=0; i<count; ++i) { 
     2490        char li_list[PJSUA_MAX_CALLS*4]; 
     2491        char tr_list[PJSUA_MAX_CALLS*4]; 
     2492        char s[32]; 
     2493        unsigned j; 
     2494        pjsua_vid_conf_port_info info; 
     2495        pjmedia_rect_size *size; 
     2496        pjmedia_ratio *fps; 
     2497 
     2498        pjsua_vid_conf_get_port_info(id[i], &info); 
     2499        size = &info.format.det.vid.size; 
     2500        fps = &info.format.det.vid.fps; 
     2501 
     2502        li_list[0] = '\0'; 
     2503        for (j=0; j<info.listener_cnt; ++j) { 
     2504            char s[10]; 
     2505            pj_ansi_snprintf(s, sizeof(s), "%d%s", 
     2506                             info.listeners[j], 
     2507                             (j==info.listener_cnt-1)?"":","); 
     2508            pj_ansi_strcat(li_list, s); 
     2509        } 
     2510        tr_list[0] = '\0'; 
     2511        for (j=0; j<info.transmitter_cnt; ++j) { 
     2512            char s[10]; 
     2513            pj_ansi_snprintf(s, sizeof(s), "%d%s", info.transmitters[j], 
     2514                             (j==info.transmitter_cnt-1)?"":","); 
     2515            pj_ansi_strcat(tr_list, s); 
     2516        } 
     2517        pjmedia_fourcc_name(info.format.id, s); 
     2518        s[4] = ' '; 
     2519        pj_ansi_snprintf(s+5, sizeof(s)-5, "%dx%d@%.1f", 
     2520                         size->w, size->h, (float)(fps->num*1.0/fps->denum)); 
     2521        PJ_LOG(3,(THIS_FILE,"%3d %.*s%.*s %s%.*s %s%.*s %s\n", 
     2522                            id[i], 
     2523                            (int)info.name.slen, info.name.ptr, 
     2524                            22-(int)info.name.slen, "                   ", 
     2525                            s, 
     2526                            20-pj_ansi_strlen(s), "                    ", 
     2527                            tr_list, 
     2528                            12-pj_ansi_strlen(tr_list), "            ", 
     2529                            li_list)); 
     2530    } 
     2531    return PJ_SUCCESS; 
     2532} 
     2533 
     2534static pj_status_t cmd_vid_conf_connect(pj_cli_cmd_val *cval, pj_bool_t connect) 
     2535{ 
     2536    int P, Q; 
     2537 
     2538    P = (int)pj_strtol(&cval->argv[1]); 
     2539    Q = (int)pj_strtol(&cval->argv[2]); 
     2540    if (connect) 
     2541        return pjsua_vid_conf_connect(P, Q, NULL); 
     2542    else 
     2543        return pjsua_vid_conf_disconnect(P, Q); 
     2544} 
     2545 
     2546 
    24682547/* Video handler */ 
    24692548static pj_status_t cmd_video_handler(pj_cli_cmd_val *cval) 
     
    25452624    case CMD_VIDEO_WIN_RESIZE: 
    25462625        status = cmd_resize_vid_win(cval); 
     2626        break; 
     2627    case CMD_VIDEO_CONF_LIST: 
     2628        status = cmd_vid_conf_list(); 
     2629        break; 
     2630    case CMD_VIDEO_CONF_CONNECT: 
     2631    case CMD_VIDEO_CONF_DISCONNECT: 
     2632        status = cmd_vid_conf_connect(cval, (cmd_id==CMD_VIDEO_CONF_CONNECT)); 
    25472633        break; 
    25482634    } 
     
    30513137        "    </CMD>" 
    30523138        "  </CMD>" 
     3139        "  <CMD name='conf' id='6008' desc='Video conference commands'>" 
     3140        "    <CMD name='list' id='60081' desc='List all ports in video conference'/>" 
     3141        "    <CMD name='cc' id='60082' desc='Connect ports in video conference'>" 
     3142        "      <ARG name='source' type='int' desc='Source port ID'/>" 
     3143        "      <ARG name='sink' type='int' desc='Sink port ID'/>" 
     3144        "    </CMD>" 
     3145        "    <CMD name='cd' id='60083' desc='Disconnect ports in video conference'>" 
     3146        "      <ARG name='source' type='int' desc='Source port ID'/>" 
     3147        "      <ARG name='sink' type='int' desc='Sink port ID'/>" 
     3148        "    </CMD>" 
     3149        "  </CMD>" 
    30533150        "</CMD>"; 
    30543151 
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_legacy.c

    r5834 r5939  
    297297    puts("| vid win move ID X Y       Move window ID to position X,Y                    |"); 
    298298    puts("| vid win resize ID w h     Resize window ID to the specified width, height   |"); 
     299    puts("| vid conf list             List all video ports in video conference bridge   |"); 
     300    puts("| vid conf cc P Q           Connect port P to Q in the video conf bridge      |"); 
     301    puts("| vid conf cd P Q           Disconnect port P to Q in the video conf bridge   |"); 
    299302    puts("+=============================================================================+"); 
    300303    printf("| Video will be %s in the next offer/answer %s                            |\n", 
     
    592595        } else 
    593596            goto on_error; 
     597    } else if (strcmp(argv[1], "conf")==0) { 
     598        pj_status_t status; 
     599 
     600        if (argc==3 && strcmp(argv[2], "list")==0) { 
     601            pjsua_conf_port_id id[100]; 
     602            unsigned count = PJ_ARRAY_SIZE(id); 
     603 
     604            status = pjsua_vid_conf_enum_ports(id, &count); 
     605            if (status != PJ_SUCCESS) { 
     606                PJ_PERROR(1,(THIS_FILE, status, 
     607                             "Failed enumerating video conf bridge ports")); 
     608            } else { 
     609                unsigned i; 
     610                printf(" Video conference has %d ports:\n", count); 
     611                printf(" id name                   format               rx           tx    \n"); 
     612                printf(" ------------------------------------------------------------------\n"); 
     613                for (i=0; i<count; ++i) { 
     614                    char li_list[PJSUA_MAX_CALLS*4]; 
     615                    char tr_list[PJSUA_MAX_CALLS*4]; 
     616                    char s[32]; 
     617                    unsigned j; 
     618                    pjsua_vid_conf_port_info info; 
     619                    pjmedia_rect_size *size; 
     620                    pjmedia_ratio *fps; 
     621 
     622                    pjsua_vid_conf_get_port_info(id[i], &info); 
     623                    size = &info.format.det.vid.size; 
     624                    fps = &info.format.det.vid.fps; 
     625 
     626                    li_list[0] = '\0'; 
     627                    for (j=0; j<info.listener_cnt; ++j) { 
     628                        char s[10]; 
     629                        pj_ansi_snprintf(s, sizeof(s), "%d%s", 
     630                                         info.listeners[j], 
     631                                         (j==info.listener_cnt-1)?"":","); 
     632                        pj_ansi_strcat(li_list, s); 
     633                    } 
     634                    tr_list[0] = '\0'; 
     635                    for (j=0; j<info.transmitter_cnt; ++j) { 
     636                        char s[10]; 
     637                        pj_ansi_snprintf(s, sizeof(s), "%d%s", 
     638                                         info.transmitters[j], 
     639                                         (j==info.transmitter_cnt-1)?"":","); 
     640                        pj_ansi_strcat(tr_list, s); 
     641                    } 
     642                    pjmedia_fourcc_name(info.format.id, s); 
     643                    s[4] = ' '; 
     644                    pj_ansi_snprintf(s+5, sizeof(s)-5, "%dx%d@%.1f", 
     645                                     size->w, size->h, 
     646                                     (float)(fps->num*1.0/fps->denum)); 
     647                    printf("%3d %.*s%.*s %s%.*s %s%.*s %s\n", 
     648                           id[i], 
     649                           (int)info.name.slen, info.name.ptr, 
     650                           22-(int)info.name.slen, "                   ", 
     651                           s, 
     652                           20-pj_ansi_strlen(s), "                    ", 
     653                           tr_list, 
     654                           12-pj_ansi_strlen(tr_list), "            ", 
     655                           li_list); 
     656                } 
     657            } 
     658        } else if (argc==5 && strcmp(argv[2], "cc")==0) { 
     659            int P, Q; 
     660            P = atoi(argv[3]); 
     661            Q = atoi(argv[4]); 
     662            pjsua_vid_conf_connect(P, Q, NULL); 
     663        } else if (argc==5 && strcmp(argv[2], "cd")==0) { 
     664            int P, Q; 
     665            P = atoi(argv[3]); 
     666            Q = atoi(argv[4]); 
     667            pjsua_vid_conf_disconnect(P, Q); 
     668        } else { 
     669            goto on_error; 
     670        } 
    594671    } else 
    595672        goto on_error; 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r5923 r5939  
    46804680            pjsua_vid_win_id        win_in; 
    46814681 
    4682             /** The video capture device for outgoing transmission, 
    4683              *  if any, or PJMEDIA_VID_INVALID_DEV 
     4682            /** 
     4683             * The video conference port number for the call in decoding 
     4684             * direction. 
     4685             */ 
     4686            pjsua_conf_port_id      dec_slot; 
     4687 
     4688            /** 
     4689             * The video conference port number for the call in encoding 
     4690             * direction. 
     4691             */ 
     4692            pjsua_conf_port_id      enc_slot; 
     4693 
     4694            /** 
     4695             * The video capture device for outgoing transmission, 
     4696             * if any, or PJMEDIA_VID_INVALID_DEV 
    46844697             */ 
    46854698            pjmedia_vid_dev_index   cap_dev; 
     
    51685181 */ 
    51695182PJ_DECL(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id); 
     5183 
     5184 
     5185/** 
     5186 * Get the video window associated with the call. Note that this function 
     5187 * will only evaluate the first video stream in the call, to query any other 
     5188 * video stream, use pjsua_call_get_info(). 
     5189 * 
     5190 * @param call_id       Call identification. 
     5191 * 
     5192 * @return              Video window, or PJSUA_INVALID_ID when the 
     5193 *                      media has not been established or is not active. 
     5194 */ 
     5195PJ_DECL(pjsua_vid_win_id) pjsua_call_get_vid_win(pjsua_call_id call_id); 
     5196 
     5197 
     5198/** 
     5199 * Get the video conference port identification associated with the call. 
     5200 * Note that this function will only evaluate the first video stream in 
     5201 * the call, to query any other video stream, use pjsua_call_get_info(). 
     5202 * 
     5203 * @param call_id       Call identification. 
     5204 * @param dir           Port direction to be queried. Valid values are 
     5205 *                      PJMEDIA_DIR_ENCODING and PJMEDIA_DIR_DECODING only. 
     5206 * 
     5207 * @return              Conference port ID, or PJSUA_INVALID_ID when the 
     5208 *                      media has not been established or is not active. 
     5209 */ 
     5210PJ_DECL(pjsua_conf_port_id) pjsua_call_get_vid_conf_port( 
     5211                                                    pjsua_call_id call_id, 
     5212                                                    pjmedia_dir dir); 
    51705213 
    51715214/** 
     
    67046747 
    67056748/** 
    6706  * This structure descibes information about a particular media port that 
     6749 * This structure describes information about a particular media port that 
    67076750 * has been registered into the conference bridge. Application can query 
    67086751 * this info by calling #pjsua_conf_get_port_info(). 
     
    67416784 
    67426785    /** Array of listeners (in other words, ports where this port is  
    6743      *  transmitting to. 
     6786     *  transmitting to). 
    67446787     */ 
    67456788    pjsua_conf_port_id  listeners[PJSUA_MAX_CONF_PORTS]; 
     
    78087851 
    78097852/** 
     7853 * Get video conference slot ID of the specified capture device, if any. 
     7854 * 
     7855 * @param id            The capture device ID. 
     7856 * 
     7857 * @return              The video conference slot ID of the specified capture 
     7858 *                      device ID, or PJSUA_INVALID_ID if preview has not been 
     7859 *                      started for the device. 
     7860 */ 
     7861PJ_DECL(pjsua_conf_port_id) pjsua_vid_preview_get_vid_conf_port( 
     7862                                                    pjmedia_vid_dev_index id); 
     7863 
     7864/** 
    78107865 * Stop video preview. 
    78117866 * 
     
    78437898     */ 
    78447899    pjmedia_vid_dev_index rdr_dev; 
     7900 
     7901    /** 
     7902     * Renderer port ID in the video conference bridge. 
     7903     */ 
     7904    pjsua_conf_port_id slot_id; 
    78457905 
    78467906    /** 
     
    80188078 
    80198079 
     8080/* 
     8081 * Video conference API 
     8082 */ 
     8083 
     8084/** 
     8085 * This structure describes information about a particular video media port 
     8086 * that has been registered into the video conference bridge. Application 
     8087 * can query this info by calling #pjsua_vid_conf_get_port_info(). 
     8088 */ 
     8089typedef struct pjsua_vid_conf_port_info 
     8090{ 
     8091    /** Conference port number. */ 
     8092    pjsua_conf_port_id  slot_id; 
     8093 
     8094    /** Port name. */ 
     8095    pj_str_t            name; 
     8096 
     8097    /** Format. */ 
     8098    pjmedia_format      format; 
     8099 
     8100    /** Number of listeners in the array. */ 
     8101    unsigned            listener_cnt; 
     8102 
     8103    /** Array of listeners (in other words, ports where this port is  
     8104     *  transmitting to). 
     8105     */ 
     8106    pjsua_conf_port_id  listeners[PJSUA_MAX_CONF_PORTS]; 
     8107 
     8108    /** Number of transmitters in the array. */ 
     8109    unsigned            transmitter_cnt; 
     8110 
     8111    /** Array of transmitters (in other words, ports where this port is  
     8112     *  receiving from). 
     8113     */ 
     8114    pjsua_conf_port_id  transmitters[PJSUA_MAX_CONF_PORTS]; 
     8115 
     8116} pjsua_vid_conf_port_info; 
     8117 
     8118 
     8119/** 
     8120 * Get current number of active ports in the bridge. 
     8121 * 
     8122 * @return              The number. 
     8123 */ 
     8124PJ_DECL(unsigned) pjsua_vid_conf_get_active_ports(void); 
     8125 
     8126 
     8127/** 
     8128 * Enumerate all video conference ports. 
     8129 * 
     8130 * @param id            Array of conference port ID to be initialized. 
     8131 * @param count         On input, specifies max elements in the array. 
     8132 *                      On return, it contains actual number of elements 
     8133 *                      that have been initialized. 
     8134 * 
     8135 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     8136 */ 
     8137PJ_DECL(pj_status_t) pjsua_vid_conf_enum_ports(pjsua_conf_port_id id[], 
     8138                                               unsigned *count); 
     8139 
     8140 
     8141/** 
     8142 * Get information about the specified video conference port 
     8143 * 
     8144 * @param port_id       Port identification. 
     8145 * @param info          Pointer to store the port info. 
     8146 * 
     8147 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     8148 */ 
     8149PJ_DECL(pj_status_t) pjsua_vid_conf_get_port_info( 
     8150                                            pjsua_conf_port_id port_id, 
     8151                                            pjsua_vid_conf_port_info *info); 
     8152 
     8153 
     8154/** 
     8155 * Add arbitrary video media port to PJSUA's video conference bridge. 
     8156 * Application can use this function to add the media port that it creates. 
     8157 * For media ports that are created by PJSUA-LIB (such as calls, AVI player), 
     8158 * PJSUA-LIB will automatically add the port to the bridge. 
     8159 * 
     8160 * @param pool          Pool to use. 
     8161 * @param port          Media port to be added to the bridge. 
     8162 * @param param         Currently this is not used and must be set to NULL. 
     8163 * @param p_id          Optional pointer to receive the conference  
     8164 *                      slot id. 
     8165 * 
     8166 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     8167 */ 
     8168PJ_DECL(pj_status_t) pjsua_vid_conf_add_port(pj_pool_t *pool, 
     8169                                             pjmedia_port *port, 
     8170                                             const void *param, 
     8171                                             pjsua_conf_port_id *p_id); 
     8172 
     8173 
     8174/** 
     8175 * Remove arbitrary slot from the video conference bridge. Application should 
     8176 * only call this function if it registered the port manually with previous 
     8177 * call to #pjsua_vid_conf_add_port(). 
     8178 * 
     8179 * @param port_id       The slot id of the port to be removed. 
     8180 * 
     8181 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     8182 */ 
     8183PJ_DECL(pj_status_t) pjsua_vid_conf_remove_port(pjsua_conf_port_id port_id); 
     8184 
     8185 
     8186/** 
     8187 * Establish unidirectional video flow from souce to sink. One source 
     8188 * may transmit to multiple destinations/sink. And if multiple 
     8189 * sources are transmitting to the same sink, the video will be mixed 
     8190 * together (currently, each source will be resized down so all sources will 
     8191 * occupy the same portion in the sink video frame). Source and sink may 
     8192 * refer to the same ID, effectively looping the media. 
     8193 * 
     8194 * If bidirectional media flow is desired, application needs to call 
     8195 * this function twice, with the second one having the arguments 
     8196 * reversed. 
     8197 * 
     8198 * @param source        Port ID of the source media/transmitter. 
     8199 * @param sink          Port ID of the destination media/received. 
     8200 * @param param         Currently this is not used and must be set to NULL. 
     8201 * 
     8202 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     8203 */ 
     8204PJ_DECL(pj_status_t) pjsua_vid_conf_connect(pjsua_conf_port_id source, 
     8205                                            pjsua_conf_port_id sink, 
     8206                                            const void *param); 
     8207 
     8208 
     8209/** 
     8210 * Disconnect video flow from the source to destination port. 
     8211 * 
     8212 * @param source        Port ID of the source media/transmitter. 
     8213 * @param sink          Port ID of the destination media/received. 
     8214 * 
     8215 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     8216 */ 
     8217PJ_DECL(pj_status_t) pjsua_vid_conf_disconnect(pjsua_conf_port_id source, 
     8218                                               pjsua_conf_port_id sink); 
     8219 
     8220 
    80208221 
    80218222/* end of VIDEO API */ 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r5923 r5939  
    6060        struct { 
    6161            pjmedia_vid_stream  *stream;    /**< The video stream.          */ 
     62            pjsua_conf_port_id   strm_enc_slot; /**< Stream encode slot     */ 
     63            pjsua_conf_port_id   strm_dec_slot; /**< Stream decode slot     */ 
    6264            pjsua_vid_win_id     cap_win_id;/**< The video capture window   */ 
    6365            pjsua_vid_win_id     rdr_win_id;/**< The video render window    */ 
     
    404406    pjmedia_vid_port            *vp_cap;        /**< Capture vidport.   */ 
    405407    pjmedia_vid_port            *vp_rend;       /**< Renderer vidport   */ 
    406     pjmedia_port                *tee;           /**< Video tee          */ 
     408    pjsua_conf_port_id           cap_slot;      /**< Capturer conf slot */ 
     409    pjsua_conf_port_id           rend_slot;     /**< Renderer conf slot */ 
    407410    pjmedia_vid_dev_index        preview_cap_id;/**< Capture dev id     */ 
    408411    pj_bool_t                    preview_running;/**< Preview is started*/ 
     
    513516    /* For keeping video device settings */ 
    514517#if PJSUA_HAS_VIDEO 
     518    pjmedia_vid_conf     *vid_conf; 
    515519    pj_uint32_t           vid_caps[PJMEDIA_VID_DEV_MAX_DEVS]; 
    516520    pjmedia_vid_dev_param vid_param[PJMEDIA_VID_DEV_MAX_DEVS]; 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r5937 r5939  
    153153        call_med->strm.v.cap_win_id = PJSUA_INVALID_ID; 
    154154        call_med->strm.v.rdr_win_id = PJSUA_INVALID_ID; 
     155        call_med->strm.v.strm_dec_slot = PJSUA_INVALID_ID; 
     156        call_med->strm.v.strm_enc_slot = PJSUA_INVALID_ID; 
    155157        call_med->call = call; 
    156158        call_med->idx = i; 
     
    22242226            info->media[info->media_cnt].stream.vid.win_in = 
    22252227                                                call_med->strm.v.rdr_win_id; 
     2228 
     2229            info->media[info->media_cnt].stream.vid.dec_slot = 
     2230                                                call_med->strm.v.strm_dec_slot; 
     2231            info->media[info->media_cnt].stream.vid.enc_slot = 
     2232                                                call_med->strm.v.strm_enc_slot; 
    22262233 
    22272234            if (call_med->strm.v.cap_win_id != PJSUA_INVALID_ID) { 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r5923 r5939  
    14771477                        call_med->last_req_keyframe = now; 
    14781478                    } 
     1479                } 
     1480            } 
     1481            break; 
     1482 
     1483        case PJMEDIA_EVENT_FMT_CHANGED: 
     1484            if (call_med->strm.v.rdr_win_id != PJSUA_INVALID_ID) { 
     1485                pjsua_vid_win *w = &pjsua_var.win[call_med->strm.v.rdr_win_id]; 
     1486                if (event->src == w->vp_rend) { 
     1487                    /* Renderer just changed format, reconnect stream */ 
     1488                    pjsua_vid_conf_disconnect(call_med->strm.v.strm_dec_slot, 
     1489                                              w->rend_slot); 
     1490                    pjsua_vid_conf_connect(call_med->strm.v.strm_dec_slot, 
     1491                                           w->rend_slot, NULL); 
    14791492                } 
    14801493            } 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c

    r5842 r5939  
    2727 
    2828#define ENABLE_EVENT            1 
    29 #define VID_TEE_MAX_PORT        (PJSUA_MAX_CALLS + 1) 
    3029 
    3130#define PJSUA_SHOW_WINDOW       1 
     
    6665        PJ_PERROR(1,(THIS_FILE, status, 
    6766                     "Error creating PJMEDIA video codec manager")); 
     67        goto on_error; 
     68    } 
     69 
     70    status = pjmedia_vid_conf_create(pjsua_var.pool, NULL, 
     71                                     &pjsua_var.vid_conf); 
     72    if (status != PJ_SUCCESS) { 
     73        PJ_PERROR(1,(THIS_FILE, status, 
     74                     "Error creating PJMEDIA video conference bridge")); 
    6875        goto on_error; 
    6976    } 
     
    139146            pjsua_var.win[i].pool = NULL; 
    140147        } 
     148    } 
     149 
     150    if (pjsua_var.vid_conf) { 
     151        pjmedia_vid_conf_destroy(pjsua_var.vid_conf); 
     152        pjsua_var.vid_conf = NULL; 
    141153    } 
    142154 
     
    515527} 
    516528 
     529/* 
     530 * Get video conference slot ID of the specified capture device. 
     531 */ 
     532PJ_DEF(pjsua_conf_port_id) pjsua_vid_preview_get_vid_conf_port( 
     533                                                    pjmedia_vid_dev_index id) 
     534{ 
     535    pjsua_vid_win_id wid; 
     536    pjsua_vid_win *w; 
     537 
     538    wid = vid_preview_get_win(id, PJ_TRUE); 
     539    if (wid == PJSUA_INVALID_ID) 
     540        return PJSUA_INVALID_ID; 
     541 
     542    w = &pjsua_var.win[wid]; 
     543    return w->cap_slot; 
     544} 
     545 
     546 
    517547PJ_DEF(void) pjsua_vid_win_reset(pjsua_vid_win_id wid) 
    518548{ 
     
    528558 
    529559/* Allocate and initialize pjsua video window: 
    530  * - If the type is preview, video capture, tee, and render 
    531  *   will be instantiated. 
    532  * - If the type is stream, only renderer will be created. 
     560 * - If the type is preview: capture port and render port 
     561 *   will be instantiated, and connected via conf. 
     562 * - If the type is stream: only render port will be created. 
    533563 */ 
    534564static pj_status_t create_vid_win(pjsua_vid_win_type type, 
     
    673703 
    674704        /* Create capture video port */ 
    675         vp_param.active = PJ_TRUE; 
     705        vp_param.active = PJ_FALSE; 
    676706        vp_param.vidparam.dir = PJMEDIA_DIR_CAPTURE; 
    677707 
     
    703733        fmt = &fmt_; 
    704734 
    705         /* Create video tee */ 
    706         status = pjmedia_vid_tee_create(w->pool, fmt, VID_TEE_MAX_PORT, 
    707                                         &w->tee); 
    708         if (status != PJ_SUCCESS) 
    709             goto on_error; 
    710  
    711         /* Connect capturer to the video tee */ 
    712         status = pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE); 
     735        /* Register capturer to the video conf */ 
     736        status = pjsua_vid_conf_add_port( 
     737                                w->pool, 
     738                                pjmedia_vid_port_get_passive_port(w->vp_cap), 
     739                                NULL, &w->cap_slot); 
    713740        if (status != PJ_SUCCESS) 
    714741            goto on_error; 
     
    739766            goto on_error; 
    740767 
    741         vp_param.active = (w->type == PJSUA_WND_TYPE_STREAM); 
     768        vp_param.active = PJ_FALSE; 
    742769        vp_param.vidparam.dir = PJMEDIA_DIR_RENDER; 
    743770        vp_param.vidparam.fmt = *fmt; 
     
    756783            goto on_error; 
    757784 
    758         /* For preview window, connect capturer & renderer (via tee) */ 
     785        /* Register renderer to the video conf */ 
     786        status = pjsua_vid_conf_add_port( 
     787                                w->pool, 
     788                                pjmedia_vid_port_get_passive_port(w->vp_rend), 
     789                                NULL, &w->rend_slot); 
     790        if (status != PJ_SUCCESS) 
     791            goto on_error; 
     792 
     793        /* For preview window, connect capturer & renderer (via conf) */ 
    759794        if (w->type == PJSUA_WND_TYPE_PREVIEW) { 
    760             pjmedia_port *rend_port; 
    761  
    762             rend_port = pjmedia_vid_port_get_passive_port(w->vp_rend); 
    763             status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, rend_port); 
     795            status = pjsua_vid_conf_connect(w->cap_slot, w->rend_slot, NULL); 
    764796            if (status != PJ_SUCCESS) 
    765797                goto on_error; 
     
    799831 
    800832    if (w->vp_cap) { 
     833        pjsua_vid_conf_remove_port(w->cap_slot); 
    801834        pjmedia_event_unsubscribe(NULL, &call_media_on_event, NULL, 
    802835                                  w->vp_cap); 
    803836        pjmedia_vid_port_stop(w->vp_cap); 
    804         pjmedia_vid_port_disconnect(w->vp_cap); 
    805837        pjmedia_vid_port_destroy(w->vp_cap); 
    806838    } 
    807839    if (w->vp_rend) { 
     840        pjsua_vid_conf_remove_port(w->rend_slot); 
    808841        pjmedia_event_unsubscribe(NULL, &call_media_on_event, NULL, 
    809842                                  w->vp_rend); 
     
    811844        pjmedia_vid_port_destroy(w->vp_rend); 
    812845    } 
    813     if (w->tee) { 
    814         pjmedia_port_destroy(w->tee); 
    815     } 
    816846    pjsua_vid_win_reset(wid); 
    817847 
     
    850880    call_med->strm.v.rdr_dev = acc->cfg.vid_rend_dev; 
    851881    call_med->strm.v.cap_dev = acc->cfg.vid_cap_dev; 
     882    call_med->strm.v.strm_dec_slot = PJSUA_INVALID_ID; 
     883    call_med->strm.v.strm_enc_slot = PJSUA_INVALID_ID; 
    852884    if (call_med->strm.v.rdr_dev == PJMEDIA_VID_DEFAULT_RENDER_DEV) { 
    853885        pjmedia_vid_dev_info info; 
     
    9791011            pj_log_push_indent(); 
    9801012 
     1013            /* Retrieve stream decoding port */ 
    9811014            status = pjmedia_vid_stream_get_port(call_med->strm.v.stream, 
    9821015                                                 PJMEDIA_DIR_DECODING, 
     
    10101043#endif 
    10111044             
    1012             /* Connect renderer to stream */ 
    1013             status = pjmedia_vid_port_connect(w->vp_rend, media_port, 
    1014                                               PJ_FALSE); 
     1045            /* Register renderer to stream events */ 
     1046            pjmedia_vid_port_subscribe_event(w->vp_rend, media_port); 
     1047 
     1048            /* Register stream decoding to conf, using tmp_pool should be fine 
     1049             * as bridge will create its own pool (using tmp_pool factory). 
     1050             */ 
     1051            status = pjsua_vid_conf_add_port(tmp_pool, media_port, NULL, 
     1052                                             &call_med->strm.v.strm_dec_slot); 
     1053            if (status != PJ_SUCCESS) { 
     1054                pj_log_pop_indent(); 
     1055                goto on_error; 
     1056            } 
     1057 
     1058            /* Connect stream to renderer (via conf) */ 
     1059            status = pjsua_vid_conf_connect(call_med->strm.v.strm_dec_slot, 
     1060                                            w->rend_slot, NULL); 
    10151061            if (status != PJ_SUCCESS) { 
    10161062                pj_log_pop_indent(); 
     
    10421088            pj_log_push_indent(); 
    10431089 
     1090            /* Retrieve stream encoding port */ 
    10441091            status = pjmedia_vid_stream_get_port(call_med->strm.v.stream, 
    10451092                                                 PJMEDIA_DIR_ENCODING, 
     
    10791126#endif 
    10801127             
    1081             /* Connect stream to capturer (via video window tee) */ 
    1082             status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, media_port); 
     1128            /* Register stream encoding to conf, using tmp_pool should be fine 
     1129             * as bridge will create its own pool (using tmp_pool factory). 
     1130             */ 
     1131            status = pjsua_vid_conf_add_port(tmp_pool, media_port, NULL, 
     1132                                             &call_med->strm.v.strm_enc_slot); 
     1133            if (status != PJ_SUCCESS) { 
     1134                pj_log_pop_indent(); 
     1135                goto on_error; 
     1136            } 
     1137 
     1138            /* Connect capturer to stream encoding (via conf) */ 
     1139            status = pjsua_vid_conf_connect(w->cap_slot, 
     1140                                            call_med->strm.v.strm_enc_slot, 
     1141                                            NULL); 
    10831142            if (status != PJ_SUCCESS) { 
    10841143                pj_log_pop_indent(); 
     
    11331192    pj_log_push_indent(); 
    11341193     
     1194    /* Unregister video stream ports (encode+decode) from conference */ 
     1195    pjsua_vid_conf_remove_port(call_med->strm.v.strm_enc_slot); 
     1196    pjsua_vid_conf_remove_port(call_med->strm.v.strm_dec_slot); 
     1197 
    11351198    pjmedia_vid_stream_send_rtcp_bye(strm); 
    11361199 
    11371200    if (call_med->strm.v.cap_win_id != PJSUA_INVALID_ID) { 
    1138         pjmedia_port *media_port; 
    11391201        pjsua_vid_win *w = &pjsua_var.win[call_med->strm.v.cap_win_id]; 
    1140         pj_status_t status; 
    1141  
    1142         /* Stop the capture before detaching stream and unsubscribing event */ 
    1143         pjmedia_vid_port_stop(w->vp_cap); 
    1144  
    1145         /* Disconnect video stream from capture device */ 
    1146         status = pjmedia_vid_stream_get_port(call_med->strm.v.stream, 
    1147                                              PJMEDIA_DIR_ENCODING, 
    1148                                              &media_port); 
    1149         if (status == PJ_SUCCESS) { 
    1150             pjmedia_vid_tee_remove_dst_port(w->tee, media_port); 
    1151         } 
    1152  
    1153         /* Unsubscribe event */ 
     1202 
     1203        /* Unsubscribe event */ 
    11541204        pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med, 
    11551205                                  w->vp_cap); 
    11561206 
    1157         /* Re-start capture again, if it is used by other stream */ 
    1158         if (w->ref_cnt > 1) 
    1159             pjmedia_vid_port_start(w->vp_cap); 
    1160  
     1207        /* Decrement ref count of preview video window */ 
    11611208        dec_vid_win(call_med->strm.v.cap_win_id); 
    11621209        call_med->strm.v.cap_win_id = PJSUA_INVALID_ID; 
     
    11661213        pjsua_vid_win *w = &pjsua_var.win[call_med->strm.v.rdr_win_id]; 
    11671214 
    1168         /* Stop the render before unsubscribing event */ 
     1215        /* Unsubscribe event, but stop the render first */ 
    11691216        pjmedia_vid_port_stop(w->vp_rend); 
    11701217        pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med, 
    11711218                                  w->vp_rend); 
    11721219 
     1220        /* Decrement ref count of stream video window */ 
    11731221        dec_vid_win(call_med->strm.v.rdr_win_id); 
    11741222        call_med->strm.v.rdr_win_id = PJSUA_INVALID_ID; 
     
    14321480 
    14331481    wi->rdr_dev = vparam.rend_id; 
     1482    wi->slot_id = w->rend_slot; 
    14341483    wi->hwnd = vparam.window; 
    14351484    wi->show = !vparam.window_hide; 
     
    20432092        w->preview_cap_id = cap_dev; 
    20442093        call_med->strm.v.cap_dev = cap_dev; 
     2094        /* Yay, change capturer done! */ 
    20452095        return PJ_SUCCESS; 
    20462096    } 
    20472097 
    2048     /* No it doesn't support fast switching. Do slow switching then.. */ 
     2098    /* Oh no, it doesn't support fast switching. Do normal change then, 
     2099     * i.e: remove the old and create a new capture. 
     2100     */ 
    20492101    status = pjmedia_vid_stream_get_port(call_med->strm.v.stream, 
    20502102                                         PJMEDIA_DIR_ENCODING, &media_port); 
     
    20552107                              w->vp_cap); 
    20562108     
    2057     /* temporarily disconnect while we operate on the tee. */ 
    2058     pjmedia_vid_port_disconnect(w->vp_cap); 
    2059  
    2060     /* = Detach stream port from the old capture device's tee = */ 
    2061     status = pjmedia_vid_tee_remove_dst_port(w->tee, media_port); 
    2062     if (status != PJ_SUCCESS) { 
    2063         /* Something wrong, assume that media_port has been removed 
    2064          * and continue. 
    2065          */ 
    2066         PJ_PERROR(4,(THIS_FILE, status, 
    2067                      "Warning: call %d: unable to remove video from tee", 
    2068                      call->index)); 
    2069     } 
    2070  
    2071     /* Reconnect again immediately. We're done with w->tee */ 
    2072     pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE); 
     2109    /* Disconnect the old capture device to stream encoding port */ 
     2110    status = pjsua_vid_conf_disconnect(w->cap_slot, 
     2111                                       call_med->strm.v.strm_enc_slot); 
     2112    if (status != PJ_SUCCESS) 
     2113        return status; 
     2114 
    20732115 
    20742116    /* = Attach stream port to the new capture device = */ 
     
    20982140    inc_vid_win(new_wid); 
    20992141    new_w = &pjsua_var.win[new_wid]; 
    2100      
    2101     /* Connect stream to capturer (via video window tee) */ 
    2102     status = pjmedia_vid_tee_add_dst_port2(new_w->tee, 0, media_port); 
    2103     if (status != PJ_SUCCESS) 
    2104         goto on_error; 
    21052142 
    21062143    if (new_w->vp_rend) { 
     
    21232160    } 
    21242161 
     2162    /* Connect capturer to stream encoding port (via conf) */ 
     2163    status = pjsua_vid_conf_connect(new_w->cap_slot, 
     2164                                    call_med->strm.v.strm_enc_slot, 
     2165                                    NULL); 
     2166    if (status != PJ_SUCCESS) 
     2167        goto on_error; 
     2168 
    21252169    /* Finally */ 
    21262170    call_med->strm.v.cap_dev = cap_dev; 
     
    21392183        pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med, 
    21402184                                  new_w->vp_cap); 
    2141         /* Disconnect media port from the new capturer */ 
    2142         pjmedia_vid_tee_remove_dst_port(new_w->tee, media_port); 
     2185 
    21432186        /* Release the new capturer */ 
    21442187        dec_vid_win(new_wid); 
     
    21462189 
    21472190    /* Revert back to the old capturer */ 
    2148     pjmedia_vid_port_disconnect(w->vp_cap); 
    2149     status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, media_port); 
    2150     pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE); 
     2191    status = pjsua_vid_conf_connect(w->cap_slot, 
     2192                                    call_med->strm.v.strm_enc_slot, NULL); 
    21512193    if (status != PJ_SUCCESS) 
    21522194        return status; 
     
    23722414} 
    23732415 
     2416 
     2417/***************************************************************************** 
     2418 * Video conference 
     2419 */ 
     2420 
     2421/* 
     2422 * Get current number of active ports in the bridge. 
     2423 */ 
     2424PJ_DEF(unsigned) pjsua_vid_conf_get_active_ports(void) 
     2425{ 
     2426    return pjmedia_vid_conf_get_port_count(pjsua_var.vid_conf); 
     2427} 
     2428 
     2429 
     2430/* 
     2431 * Enumerate all video conference ports. 
     2432 */ 
     2433PJ_DEF(pj_status_t) pjsua_vid_conf_enum_ports( pjsua_conf_port_id id[], 
     2434                                               unsigned *count) 
     2435{ 
     2436    return pjmedia_vid_conf_enum_ports(pjsua_var.vid_conf, 
     2437                                       (unsigned*)id, count); 
     2438} 
     2439 
     2440 
     2441/* 
     2442 * Get information about the specified video conference port 
     2443 */ 
     2444PJ_DEF(pj_status_t) pjsua_vid_conf_get_port_info( 
     2445                                            pjsua_conf_port_id port_id, 
     2446                                            pjsua_vid_conf_port_info *info) 
     2447{ 
     2448    pjmedia_vid_conf_port_info cinfo; 
     2449    unsigned i; 
     2450    pj_status_t status; 
     2451 
     2452    status = pjmedia_vid_conf_get_port_info(pjsua_var.vid_conf, 
     2453                                            (unsigned)port_id, &cinfo); 
     2454    if (status != PJ_SUCCESS) 
     2455        return status; 
     2456 
     2457    pj_bzero(info, sizeof(*info)); 
     2458    info->slot_id = port_id; 
     2459    info->name = cinfo.name; 
     2460    pjmedia_format_copy(&info->format, &cinfo.format); 
     2461 
     2462    /* Build array of listeners */ 
     2463    info->listener_cnt = cinfo.listener_cnt; 
     2464    for (i=0; i<cinfo.listener_cnt; ++i) { 
     2465        info->listeners[i] = cinfo.listener_slots[i]; 
     2466    } 
     2467 
     2468    /* Build array of transmitters */ 
     2469    info->transmitter_cnt = cinfo.transmitter_cnt; 
     2470    for (i=0; i<cinfo.transmitter_cnt; ++i) { 
     2471        info->transmitters[i] = cinfo.transmitter_slots[i]; 
     2472    } 
     2473 
     2474    return PJ_SUCCESS; 
     2475 
     2476} 
     2477 
     2478 
     2479/* 
     2480 * Add arbitrary video media port to PJSUA's video conference bridge. 
     2481 */ 
     2482PJ_DEF(pj_status_t) pjsua_vid_conf_add_port( pj_pool_t *pool, 
     2483                                             pjmedia_port *port, 
     2484                                             const void *param, 
     2485                                             pjsua_conf_port_id *p_id) 
     2486{ 
     2487    pj_status_t status; 
     2488 
     2489    PJ_UNUSED_ARG(param); 
     2490 
     2491    status = pjmedia_vid_conf_add_port(pjsua_var.vid_conf, pool, 
     2492                                       port, NULL, NULL, (unsigned*)p_id); 
     2493    if (status != PJ_SUCCESS) { 
     2494        if (p_id) 
     2495            *p_id = PJSUA_INVALID_ID; 
     2496    } 
     2497 
     2498    return status; 
     2499} 
     2500 
     2501 
     2502/* 
     2503 * Remove arbitrary slot from the video conference bridge. 
     2504 */ 
     2505PJ_DEF(pj_status_t) pjsua_vid_conf_remove_port(pjsua_conf_port_id id) 
     2506{ 
     2507    return pjmedia_vid_conf_remove_port(pjsua_var.vid_conf, (unsigned)id); 
     2508} 
     2509 
     2510 
     2511/* 
     2512 * Establish unidirectional video flow from souce to sink. 
     2513 */ 
     2514PJ_DEF(pj_status_t) pjsua_vid_conf_connect( pjsua_conf_port_id source, 
     2515                                            pjsua_conf_port_id sink, 
     2516                                            const void *param) 
     2517{ 
     2518    PJ_UNUSED_ARG(param); 
     2519    return pjmedia_vid_conf_connect_port(pjsua_var.vid_conf, source, sink, 
     2520                                         NULL); 
     2521} 
     2522 
     2523 
     2524/* 
     2525 * Disconnect video flow from the source to destination port. 
     2526 */ 
     2527PJ_DEF(pj_status_t) pjsua_vid_conf_disconnect(pjsua_conf_port_id source, 
     2528                                              pjsua_conf_port_id sink) 
     2529{ 
     2530    return pjmedia_vid_conf_disconnect_port(pjsua_var.vid_conf, source, sink); 
     2531} 
     2532 
     2533/* 
     2534 * Get the video window associated with the call. 
     2535 */ 
     2536PJ_DEF(pjsua_vid_win_id) pjsua_call_get_vid_win(pjsua_call_id call_id) 
     2537{ 
     2538    pjsua_call *call; 
     2539    pjsua_vid_win_id wid = PJSUA_INVALID_ID; 
     2540    unsigned i; 
     2541 
     2542    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     2543                     PJ_EINVAL); 
     2544 
     2545    /* Use PJSUA_LOCK() instead of acquire_call(): 
     2546     *  https://trac.pjsip.org/repos/ticket/1371 
     2547     */ 
     2548    PJSUA_LOCK(); 
     2549 
     2550    if (!pjsua_call_is_active(call_id)) 
     2551        goto on_return; 
     2552 
     2553    call = &pjsua_var.calls[call_id]; 
     2554    for (i = 0; i < call->med_cnt; ++i) { 
     2555        if (call->media[i].type == PJMEDIA_TYPE_VIDEO && 
     2556            (call->media[i].dir & PJMEDIA_DIR_DECODING)) 
     2557        { 
     2558            wid = call->media[i].strm.v.rdr_win_id; 
     2559            break; 
     2560        } 
     2561    } 
     2562 
     2563on_return: 
     2564    PJSUA_UNLOCK(); 
     2565 
     2566    return wid; 
     2567} 
     2568 
     2569 
     2570/* 
     2571 * Get the video conference port identification associated with the call. 
     2572 */ 
     2573PJ_DEF(pjsua_conf_port_id) pjsua_call_get_vid_conf_port( 
     2574                                                    pjsua_call_id call_id, 
     2575                                                    pjmedia_dir dir) 
     2576{ 
     2577    pjsua_call *call; 
     2578    pjsua_conf_port_id port_id = PJSUA_INVALID_ID; 
     2579    unsigned i; 
     2580 
     2581    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     2582                     PJ_EINVAL); 
     2583    PJ_ASSERT_RETURN(dir==PJMEDIA_DIR_ENCODING || dir==PJMEDIA_DIR_DECODING, 
     2584                     PJ_EINVAL); 
     2585 
     2586    /* Use PJSUA_LOCK() instead of acquire_call(): 
     2587     *  https://trac.pjsip.org/repos/ticket/1371 
     2588     */ 
     2589    PJSUA_LOCK(); 
     2590 
     2591    if (!pjsua_call_is_active(call_id)) 
     2592        goto on_return; 
     2593 
     2594    call = &pjsua_var.calls[call_id]; 
     2595    for (i = 0; i < call->med_cnt; ++i) { 
     2596        if (call->media[i].type == PJMEDIA_TYPE_VIDEO && 
     2597            (call->media[i].dir & dir)) 
     2598        { 
     2599            port_id = (dir==PJMEDIA_DIR_ENCODING)? 
     2600                                    call->media[i].strm.v.strm_enc_slot : 
     2601                                    call->media[i].strm.v.strm_dec_slot; 
     2602            break; 
     2603        } 
     2604    } 
     2605 
     2606on_return: 
     2607    PJSUA_UNLOCK(); 
     2608 
     2609    return port_id; 
     2610} 
     2611 
     2612 
    23742613#endif /* PJSUA_HAS_VIDEO */ 
    23752614 
Note: See TracChangeset for help on using the changeset viewer.