Changeset 3457


Ignore:
Timestamp:
Mar 17, 2011 4:34:43 AM (8 years ago)
Author:
bennylp
Message:

Modifications in PJSUA-LIB to support multiple media streams (multiple audio and/or video) and dynamic creation of media transports. This closed #1185 and closed #1201.

1185: Dynamic creation of media transports
============================================
Done:

  • media transports are created on demand now

Todo:

  • media transport creation is still blocking

1201: Video support in PJSUA-LIB
===================================
Done:

  • call now supports N media (N audio and M video)
  • number of audio/video streams is configurable per acc
  • extra audio stream info in pjsua_call_info to support multiple audio streams

in one call

  • video subsys and ffmpeg initialization in PJSUA-LIB
  • ability to offer and create video SDP answer
  • "dq" for more than 1 audio streams
  • introducing pjsua_state and pjsua_get_state()

API change:

  • on_stream_created() and on_stream_destroyed() callbacks: changed session to

stream

Todo:

  • many others features are disabled, just search for DISABLED_FOR_TICKET_1185

macro (these have also been added to ticket #1193 (Issues & Todos)). Notable
missing features are:

  • creation of duplicate SDP m= lines for optional SRTP
  • mm.. that's it?
  • whole lot of testings

pjsua:
===============

  • Added --extra-audio and --video options. Specify these more than once and

each time an extra audio/video streams will be added. :)

Location:
pjproject/branches/projects/2.0-dev
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/2.0-dev/build.mak.in

    r3393 r3457  
    5959@ac_build_mak_vars@ 
    6060 
     61# 
     62# Video 
     63# Note: there are duplicated macros in pjmedia/os-auto.mak.in (and that's not 
     64#       good! 
     65 
     66# SDL flags 
     67SDL_CFLAGS = @ac_sdl_cflags@ 
     68SDL_LDFLAGS = @ac_sdl_ldflags@ 
     69 
     70# FFMPEG dlags 
     71FFMPEG_CFLAGS = @ac_ffmpeg_cflags@  
     72FFMPEG_LDFLAGS =  @ac_ffmpeg_ldflags@ 
     73 
     74# Video4Linux2 
     75V4L2_CFLAGS = @ac_v4l2_cflags@ 
     76V4L2_LDFLAGS = @ac_v4l2_ldflags@ 
     77 
     78# QT 
     79AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@ 
     80QT_CFLAGS = @ac_qt_cflags@ 
     81 
     82# iOS 
     83IOS_CFLAGS = @ac_ios_cflags@ 
     84 
     85# PJMEDIA features exclusion 
     86PJ_VIDEO_CFLAGS += $(SDL_CFLAGS) $(FFMPEG_CFLAGS) $(V4L2_CFLAGS) $(QT_CFLAGS) \ 
     87                   $(IOS_CFLAGS) 
     88PJ_VIDEO_LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS) 
     89 
     90 
    6191# CFLAGS, LDFLAGS, and LIBS to be used by applications 
    6292export PJDIR := @ac_pjdir@ 
     
    6595export APP_CFLAGS := -DPJ_AUTOCONF=1\ 
    6696        @CFLAGS@\ 
     97        $(PJ_VIDEO_CFLAGS) \ 
    6798        -I$(PJDIR)/pjlib/include\ 
    6899        -I$(PJDIR)/pjlib-util/include\ 
     
    77108        -L$(PJDIR)/pjsip/lib\ 
    78109        -L$(PJDIR)/third_party/lib\ 
     110        $(PJ_VIDEO_LDFLAGS) \ 
    79111        @LDFLAGS@ 
    80112export APP_LDLIBS := -lpjsua-$(TARGET_NAME)\ 
  • pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/transport.h

    r3392 r3457  
    484484    /** Transport's "virtual" function table. */ 
    485485    pjmedia_transport_op    *op; 
     486 
     487    /** Application/user data */ 
     488    void                    *user_data; 
    486489}; 
    487490 
  • pjproject/branches/projects/2.0-dev/pjsip-apps/src/pjsua/pjsua_app.c

    r3372 r3457  
    268268 
    269269    puts  (""); 
    270     puts  ("Media Options:"); 
     270    puts  ("Audio Options:"); 
    271271    puts  ("  --add-codec=name    Manually add codec (default is to enable all)"); 
    272272    puts  ("  --dis-codec=name    Disable codec (can be specified multiple times)"); 
     
    302302    puts  ("  --no-tones          Disable audible tones"); 
    303303    puts  ("  --jb-max-size       Specify jitter buffer maximum size, in frames (default=-1)"); 
     304    puts  ("  --extra-audio       Add one more audio stream"); 
     305 
     306    puts  (""); 
     307    puts  ("Video Options:"); 
     308    puts  ("  --video             Enable video"); 
    304309 
    305310    puts  (""); 
     
    541546           OPT_AUTO_UPDATE_NAT,OPT_USE_COMPACT_FORM,OPT_DIS_CODEC, 
    542547           OPT_NO_FORCE_LR, 
    543            OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE 
     548           OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE, 
     549           OPT_VIDEO, OPT_EXTRA_AUDIO 
    544550    }; 
    545551    struct pj_getopt_option long_options[] = { 
     
    660666        { "timer-min-se", 1, 0, OPT_TIMER_MIN_SE}, 
    661667        { "outb-rid",   1, 0, OPT_OUTB_RID}, 
     668        { "video",      0, 0, OPT_VIDEO}, 
     669        { "extra-audio",0, 0, OPT_EXTRA_AUDIO}, 
    662670        { NULL, 0, 0, 0} 
    663671    }; 
     
    14161424            cfg->udp_cfg.qos_params.flags = PJ_QOS_PARAM_HAS_DSCP; 
    14171425            cfg->udp_cfg.qos_params.dscp_val = 0x18; 
     1426            break; 
     1427        case OPT_VIDEO: 
     1428            ++cur_acc->max_video_cnt; 
     1429            break; 
     1430        case OPT_EXTRA_AUDIO: 
     1431            ++cur_acc->max_audio_cnt; 
    14181432            break; 
    14191433        default: 
     
    16611675    if (acc_cfg->mwi_enabled) 
    16621676        pj_strcat2(result, "--mwi\n"); 
     1677 
     1678    /* Video & extra audio */ 
     1679    for (i=0; i<acc_cfg->max_video_cnt; ++i) { 
     1680        pj_strcat2(result, "--video\n"); 
     1681    } 
     1682    for (i=1; i<acc_cfg->max_audio_cnt; ++i) { 
     1683        pj_strcat2(result, "--extra-audio\n"); 
     1684    } 
    16631685} 
    16641686 
     
    38923914                acc_cfg.cred_info[0].data = pj_str(passwd); 
    38933915 
     3916                acc_cfg.rtp_cfg = app_config.rtp_cfg; 
     3917 
    38943918                status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL); 
    38953919                if (status != PJ_SUCCESS) { 
     
    49294953    /* Add accounts */ 
    49304954    for (i=0; i<app_config.acc_cnt; ++i) { 
     4955        app_config.acc_cfg[i].rtp_cfg = app_config.rtp_cfg; 
    49314956        status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL); 
    49324957        if (status != PJ_SUCCESS) 
     
    49604985    if (app_config.ipv6) 
    49614986        status = create_ipv6_media_transports(); 
     4987  #if DISABLED_FOR_TICKET_1185 
    49624988    else 
    49634989        status = pjsua_media_transports_create(&app_config.rtp_cfg); 
     4990  #endif 
    49644991#endif 
    49654992    if (status != PJ_SUCCESS) 
     
    52965323    } 
    52975324 
     5325#if DISABLED_FOR_TICKET_1185 
    52985326    return pjsua_media_transports_attach(tp, i, PJ_TRUE); 
    5299 } 
    5300  
     5327#else 
     5328    return PJ_ENOTSUP; 
     5329#endif 
     5330} 
     5331 
  • pjproject/branches/projects/2.0-dev/pjsip/build/Makefile

    r3319 r3457  
    7777                        pjsua_acc.o pjsua_call.o pjsua_core.o \ 
    7878                        pjsua_im.o pjsua_media.o pjsua_pres.o 
    79 export PJSUA_LIB_CFLAGS += $(_CFLAGS) 
     79export PJSUA_LIB_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS) 
    8080 
    8181 
  • pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h

    r3366 r3457  
    251251#define PJSUA_INVALID_ID            (-1) 
    252252 
     253/** Disabled features temporarily for media reorganization */ 
     254#define DISABLED_FOR_TICKET_1185        0 
     255 
    253256/** Call identification */ 
    254257typedef int pjsua_call_id; 
     
    282285#   define PJSUA_ACC_MAX_PROXIES    8 
    283286#endif 
    284  
    285 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    286287 
    287288/** 
     
    304305#endif 
    305306 
    306 #endif 
    307  
    308307/** 
    309308 * Controls whether PJSUA-LIB should add ICE media feature tag 
     
    325324#   define PJSUA_ACQUIRE_CALL_TIMEOUT 2000 
    326325#endif 
     326 
     327 
     328/** 
     329 * This enumeration represents pjsua state. 
     330 */ 
     331typedef enum pjsua_state 
     332{ 
     333    /** 
     334     * The library has not been initialized. 
     335     */ 
     336    PJSUA_STATE_NULL, 
     337 
     338    /** 
     339     * After pjsua_create() is called but before pjsua_init() is called. 
     340     */ 
     341    PJSUA_STATE_CREATED, 
     342 
     343    /** 
     344     * After pjsua_init() is called but before pjsua_start() is called. 
     345     */ 
     346    PJSUA_STATE_INIT, 
     347 
     348    /** 
     349     * After pjsua_start() is called but before everything is running. 
     350     */ 
     351    PJSUA_STATE_STARTING, 
     352 
     353    /** 
     354     * After pjsua_start() is called and before pjsua_destroy() is called. 
     355     */ 
     356    PJSUA_STATE_RUNNING, 
     357 
     358    /** 
     359     * After pjsua_destroy() is called but before the function returns. 
     360     */ 
     361    PJSUA_STATE_CLOSING 
     362 
     363} pjsua_state; 
    327364 
    328365 
     
    484521     * 
    485522     * @param call_id       Call identification. 
    486      * @param sess          Media session for the call. 
     523     * @param strm          Media stream. 
    487524     * @param stream_idx    Stream index in the media session. 
    488525     * @param p_port        On input, it specifies the media port of the 
     
    492529     */ 
    493530    void (*on_stream_created)(pjsua_call_id call_id,  
    494                               pjmedia_session *sess, 
     531                              pjmedia_stream *strm, 
    495532                              unsigned stream_idx,  
    496533                              pjmedia_port **p_port); 
     
    501538     * 
    502539     * @param call_id       Call identification. 
    503      * @param sess          Media session for the call. 
     540     * @param strm          Media stream. 
    504541     * @param stream_idx    Stream index in the media session. 
    505542     */ 
    506543    void (*on_stream_destroyed)(pjsua_call_id call_id, 
    507                                 pjmedia_session *sess,  
     544                                pjmedia_stream *strm, 
    508545                                unsigned stream_idx); 
    509546 
     
    11551192    pj_str_t        user_agent; 
    11561193 
    1157 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    11581194    /** 
    11591195     * Specify default value of secure media transport usage.  
     
    11851221 
    11861222    /** 
    1187      * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose  
     1223     * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose 
    11881224     * duplicated media in SDP offer, i.e: unsecured and secured version. 
    1189      * Otherwise, the SDP media will be composed as unsecured media but  
     1225     * Otherwise, the SDP media will be composed as unsecured media but 
    11901226     * with SDP "crypto" attribute. 
    11911227     * 
     
    11931229     */ 
    11941230    pj_bool_t        srtp_optional_dup_offer; 
    1195 #endif 
    11961231 
    11971232    /** 
     
    13511386 */ 
    13521387PJ_DECL(pj_status_t) pjsua_destroy(void); 
     1388 
     1389 
     1390/** 
     1391 * Retrieve pjsua state. 
     1392 * 
     1393 * @return      pjsua state. 
     1394 */ 
     1395PJ_DECL(pjsua_state) pjsua_get_state(void); 
    13531396 
    13541397 
     
    20942137#endif 
    20952138 
    2096  
    20972139/** 
    20982140 * This structure describes account configuration to be specified when 
     
    23852427    pj_str_t         ka_data; 
    23862428 
    2387 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
     2429    /** 
     2430     * Maximum number of simultaneous active audio streams to be allowed 
     2431     * for calls on this account. Setting this to zero will disable audio 
     2432     * in calls on this account. 
     2433     * 
     2434     * Default: 1 
     2435     */ 
     2436    unsigned         max_audio_cnt; 
     2437 
     2438    /** 
     2439     * Maximum number of simultaneous active video streams to be allowed 
     2440     * for calls on this account. Setting this to zero will disable video 
     2441     * in calls on this account. 
     2442     * 
     2443     * Default: 0 
     2444     */ 
     2445    unsigned         max_video_cnt; 
     2446 
     2447    /** 
     2448     * Media transport config. 
     2449     */ 
     2450    pjsua_transport_config rtp_cfg; 
     2451 
    23882452    /** 
    23892453     * Specify whether secure media transport should be used for this account. 
     
    24092473 
    24102474    /** 
    2411      * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose  
     2475     * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose 
    24122476     * duplicated media in SDP offer, i.e: unsecured and secured version. 
    2413      * Otherwise, the SDP media will be composed as unsecured media but  
     2477     * Otherwise, the SDP media will be composed as unsecured media but 
    24142478     * with SDP "crypto" attribute. 
    24152479     * 
     
    24172481     */ 
    24182482    pj_bool_t        srtp_optional_dup_offer; 
    2419 #endif 
    24202483 
    24212484    /** 
     
    29212984typedef enum pjsua_call_media_status 
    29222985{ 
    2923     /** Call currently has no media */ 
     2986    /** 
     2987     * Call currently has no media, or the media is not used. 
     2988     */ 
    29242989    PJSUA_CALL_MEDIA_NONE, 
    29252990 
    2926     /** The media is active */ 
     2991    /** 
     2992     * The media is active 
     2993     */ 
    29272994    PJSUA_CALL_MEDIA_ACTIVE, 
    29282995 
    2929     /** The media is currently put on hold by local endpoint */ 
     2996    /** 
     2997     * The media is currently put on hold by local endpoint 
     2998     */ 
    29302999    PJSUA_CALL_MEDIA_LOCAL_HOLD, 
    29313000 
    2932     /** The media is currently put on hold by remote endpoint */ 
     3001    /** 
     3002     * The media is currently put on hold by remote endpoint 
     3003     */ 
    29333004    PJSUA_CALL_MEDIA_REMOTE_HOLD, 
    29343005 
    2935     /** The media has reported error (e.g. ICE negotiation) */ 
     3006    /** 
     3007     * The media has reported error (e.g. ICE negotiation) 
     3008     */ 
    29363009    PJSUA_CALL_MEDIA_ERROR 
    29373010 
     
    29833056    pjsua_call_media_status media_status; 
    29843057 
    2985     /** Media direction */ 
     3058    /** Number of active audio streams in this call */ 
     3059    unsigned            audio_cnt; 
     3060 
     3061    /** Media direction of the first audio stream. */ 
    29863062    pjmedia_dir         media_dir; 
    29873063 
    2988     /** The conference port number for the call */ 
     3064    /** The conference port number for the first audio stream. */ 
    29893065    pjsua_conf_port_id  conf_slot; 
     3066 
     3067    /** Array of audio media stream information */ 
     3068    struct 
     3069    { 
     3070        /** Media index in SDP. */ 
     3071        unsigned                index; 
     3072 
     3073        /** Call media status. */ 
     3074        pjsua_call_media_status media_status; 
     3075 
     3076        /** Media direction. */ 
     3077        pjmedia_dir             media_dir; 
     3078 
     3079        /** The conference port number for the call. */ 
     3080        pjsua_conf_port_id      conf_slot; 
     3081 
     3082    } audio[4]; 
    29903083 
    29913084    /** Up-to-date call connected duration (zero when call is not  
     
    30833176 
    30843177 
     3178#if DISABLED_FOR_TICKET_1185 
    30853179/** 
    30863180 * Retrieve the media session associated with this call. Note that the media 
     
    30963190PJ_DECL(pjmedia_session*) pjsua_call_get_media_session(pjsua_call_id call_id); 
    30973191 
    3098  
    30993192/** 
    31003193 * Retrieve the media transport instance that is used for this call.  
     
    31073200 */ 
    31083201PJ_DECL(pjmedia_transport*) pjsua_call_get_media_transport(pjsua_call_id cid); 
    3109  
     3202#endif /* DISABLED_FOR_TICKET_1185 */ 
    31103203 
    31113204/** 
     
    48834976                                            const pjmedia_codec_param *param); 
    48844977 
    4885  
    4886  
    4887  
     4978#if DISABLED_FOR_TICKET_1185 
    48884979/** 
    48894980 * Create UDP media transports for all the calls. This function creates 
     
    49175008                               unsigned count, 
    49185009                               pj_bool_t auto_delete); 
     5010#endif 
    49195011 
    49205012 
  • pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua_internal.h

    r3374 r3457  
    4444} pjsua_med_tp_st; 
    4545 
     46/** Forward decl of pjsua call */ 
     47typedef struct pjsua_call pjsua_call; 
     48 
     49/** 
     50 * Call's media stream. 
     51 */ 
     52typedef struct pjsua_call_media 
     53{ 
     54    pjsua_call          *call;      /**< Parent call.                       */ 
     55    pjmedia_type         type;      /**< Media type.                        */ 
     56    unsigned             idx;       /**< This media index in parent call.   */ 
     57    pjsua_call_media_status state;  /**< Media state.                       */ 
     58    pjmedia_dir          dir;       /**< Media direction.                   */ 
     59 
     60    /** The stream */ 
     61    union { 
     62        /** Audio stream */ 
     63        struct { 
     64            pjmedia_stream *stream;    /**< The media session.              */ 
     65            int             conf_slot; /**< Slot # in conference bridge.    */ 
     66        } a; 
     67 
     68        /** Video stream */ 
     69        struct { 
     70        } v; 
     71 
     72    } strm; 
     73 
     74    pj_uint32_t          ssrc;      /**< RTP SSRC                           */ 
     75    pj_uint32_t          rtp_tx_ts; /**< Initial RTP timestamp for sender.  */ 
     76    pj_uint16_t          rtp_tx_seq;/**< Initial RTP sequence for sender.   */ 
     77    pj_uint8_t           rtp_tx_seq_ts_set; 
     78                                    /**< Bitmask flags if initial RTP sequence 
     79                                         and/or timestamp for sender are set. 
     80                                         bit 0/LSB : sequence flag 
     81                                         bit 1     : timestamp flag         */ 
     82 
     83    pjmedia_transport   *tp;        /**< Current media transport (can be 0) */ 
     84    pj_status_t          tp_ready;  /**< Media transport status.            */ 
     85    pjmedia_transport   *tp_orig;   /**< Original media transport           */ 
     86    pj_bool_t            tp_auto_del; /**< May delete media transport   */ 
     87    pjsua_med_tp_st      tp_st;     /**< Media transport state              */ 
     88    pj_sockaddr          rtp_addr;  /**< Current RTP source address 
     89                                            (used to update ICE default 
     90                                            address)                        */ 
     91    pjmedia_srtp_use     rem_srtp_use; /**< Remote's SRTP usage policy.     */ 
     92} pjsua_call_media; 
     93 
     94/** 
     95 * Maximum number of SDP "m=" lines to be supported. 
     96 */ 
     97#define PJSUA_MAX_CALL_MEDIA            PJMEDIA_MAX_SDP_MEDIA 
     98 
    4699/**  
    47100 * Structure to be attached to invite dialog.  
     
    49102 * by accessing dlg->mod_data[pjsua.mod.id]. 
    50103 */ 
    51 typedef struct pjsua_call 
     104struct pjsua_call 
    52105{ 
    53106    unsigned             index;     /**< Index in pjsua array.              */ 
     
    64117    pjsua_call_hold_type call_hold_type; /**< How to do call hold.          */ 
    65118    pj_bool_t            local_hold;/**< Flag for call-hold by local.       */ 
    66     pjsua_call_media_status media_st;/**< Media state.                      */ 
    67     pjmedia_dir          media_dir; /**< Media direction.                   */ 
    68     pjmedia_session     *session;   /**< The media session.                 */ 
    69     int                  audio_idx; /**< Index of m=audio in SDP.           */ 
    70     pj_uint32_t          ssrc;      /**< RTP SSRC                           */ 
    71     pj_uint32_t          rtp_tx_ts; /**< Initial RTP timestamp for sender.  */ 
    72     pj_uint16_t          rtp_tx_seq;/**< Initial RTP sequence for sender.   */ 
    73     pj_uint8_t           rtp_tx_seq_ts_set; 
    74                                     /**< Bitmask flags if initial RTP sequence 
    75                                          and/or timestamp for sender are set. 
    76                                          bit 0/LSB : sequence flag  
    77                                          bit 1     : timestamp flag         */ 
    78     int                  conf_slot; /**< Slot # in conference bridge.       */ 
     119 
     120    unsigned             med_cnt;   /**< Number of media in SDP.            */ 
     121    pjsua_call_media     media[PJSUA_MAX_CALL_MEDIA]; /**< Array of media   */ 
     122    unsigned             audio_idx; /**< Selected audio media.              */ 
     123 
    79124    pjsip_evsub         *xfer_sub;  /**< Xfer server subscription, if this 
    80125                                         call was triggered by xfer.        */ 
    81     pjmedia_transport   *med_tp;    /**< Current media transport.           */ 
    82     pj_status_t          med_tp_ready;/**< Media transport status.          */ 
    83     pjmedia_transport   *med_orig;  /**< Original media transport           */ 
    84     pj_bool_t            med_tp_auto_del; /**< May delete media transport   */ 
    85     pjsua_med_tp_st      med_tp_st; /**< Media transport state              */ 
    86     pj_sockaddr          med_rtp_addr; /**< Current RTP source address 
    87                                             (used to update ICE default 
    88                                             address)                        */ 
    89126    pj_stun_nat_type     rem_nat_type; /**< NAT type of remote endpoint.    */ 
    90     pjmedia_srtp_use     rem_srtp_use; /**< Remote's SRTP usage policy.     */ 
    91127 
    92128    char    last_text_buf_[128];    /**< Buffer for last_text.              */ 
     
    100136                                          contains multiple codecs.         */ 
    101137 
    102 } pjsua_call; 
     138}; 
    103139 
    104140 
     
    271307    pj_pool_t           *pool;      /**< pjsua's private pool.          */ 
    272308    pj_mutex_t          *mutex;     /**< Mutex protection for this data */ 
     309    pjsua_state          state;     /**< Library state.                 */ 
    273310 
    274311    /* Logging: */ 
     
    402439#define PJSUA_UNLOCK() 
    403440#endif 
     441 
     442/* Core */ 
     443void pjsua_set_state(pjsua_state new_state); 
    404444 
    405445/****** 
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_acc.c

    r3377 r3457  
    119119    pjsip_auth_clt_pref_dup(pool, &dst->auth_pref, &src->auth_pref); 
    120120 
    121     dst->ka_interval = src->ka_interval; 
     121    pjsua_transport_config_dup(pool, &dst->rtp_cfg, &src->rtp_cfg); 
     122 
    122123    pj_strdup(pool, &dst->ka_data, &src->ka_data); 
    123124} 
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_call.c

    r3374 r3457  
    102102{ 
    103103    pjsua_call *call = &pjsua_var.calls[id]; 
    104  
     104    unsigned i; 
     105 
     106    pj_bzero(call, sizeof(*call)); 
    105107    call->index = id; 
    106     call->inv = NULL; 
    107     call->user_data = NULL; 
    108     call->session = NULL; 
    109     call->audio_idx = -1; 
    110     call->ssrc = pj_rand(); 
    111     call->rtp_tx_seq = 0; 
    112     call->rtp_tx_ts = 0; 
    113     call->rtp_tx_seq_ts_set = 0; 
    114     call->xfer_sub = NULL; 
    115     call->last_code = (pjsip_status_code) 0; 
    116     call->conf_slot = PJSUA_INVALID_ID; 
    117108    call->last_text.ptr = call->last_text_buf_; 
    118     call->last_text.slen = 0; 
    119     call->conn_time.sec = 0; 
    120     call->conn_time.msec = 0; 
    121     call->res_time.sec = 0; 
    122     call->res_time.msec = 0; 
    123     call->rem_nat_type = PJ_STUN_NAT_TYPE_UNKNOWN; 
    124     call->rem_srtp_use = PJMEDIA_SRTP_DISABLED; 
    125     call->local_hold = PJ_FALSE; 
    126     pj_bzero(&call->lock_codec, sizeof(call->lock_codec)); 
     109    for (i=0; i<PJ_ARRAY_SIZE(call->media); ++i) { 
     110        pjsua_call_media *call_med = &call->media[i]; 
     111        call_med->ssrc = pj_rand(); 
     112        call_med->strm.a.conf_slot = PJSUA_INVALID_ID; 
     113        call_med->call = call; 
     114        call_med->idx = i; 
     115        call_med->tp_auto_del = PJ_TRUE; 
     116    } 
    127117} 
    128118 
     
    824814    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,  
    825815                                      call->secure_level,  
    826                                       rdata->tp_info.pool, offer, 
     816                                      rdata->tp_info.pool, 
     817                                      offer, 
    827818                                      &sip_err_code); 
    828819    if (status != PJ_SUCCESS) { 
     
    11191110PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id) 
    11201111{ 
     1112    pjsua_call *call = &pjsua_var.calls[call_id]; 
    11211113    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,  
    11221114                     PJ_EINVAL); 
    1123     return pjsua_var.calls[call_id].session != NULL; 
    1124 } 
    1125  
    1126  
     1115    return call->audio_idx >= 0 && call->media[call->audio_idx].strm.a.stream; 
     1116} 
     1117 
     1118 
     1119#if DISABLED_FOR_TICKET_1185 
    11271120/* 
    11281121 * Retrieve the media session associated with this call. 
     
    11431136    PJ_ASSERT_RETURN(cid>=0 && cid<(int)pjsua_var.ua_cfg.max_calls,  
    11441137                     NULL); 
    1145     return pjsua_var.calls[cid].med_tp; 
    1146 } 
    1147  
     1138    return pjsua_var.calls[cid].tp; 
     1139} 
     1140#endif /* Removed in 2.0 */ 
    11481141 
    11491142/* Acquire lock to the specified call_id */ 
     
    12391232        return PJSUA_INVALID_ID; 
    12401233 
    1241     port_id = call->conf_slot; 
     1234    port_id = call->media[call->audio_idx].strm.a.conf_slot; 
    12421235 
    12431236    pjsip_dlg_dec_lock(dlg); 
     
    12561249    pjsua_call *call; 
    12571250    pjsip_dialog *dlg; 
     1251    unsigned mi; 
    12581252    pj_status_t status; 
    12591253 
     
    13301324    } 
    13311325     
    1332     /* media status and dir */ 
    1333     info->media_status = call->media_st; 
    1334     info->media_dir = call->media_dir; 
    1335  
     1326    /* Build array of media status and dir */ 
     1327    info->audio_cnt = 0; 
     1328    for (mi=0; mi < call->med_cnt && 
     1329               info->audio_cnt < PJ_ARRAY_SIZE(info->audio); ++mi) 
     1330    { 
     1331        pjsua_call_media *call_med = &call->media[mi]; 
     1332        if (call_med->type != PJMEDIA_TYPE_AUDIO) 
     1333            continue; 
     1334        info->audio[info->audio_cnt].index = mi; 
     1335        info->audio[info->audio_cnt].media_status = call_med->state; 
     1336        info->audio[info->audio_cnt].media_dir = call_med->dir; 
     1337        info->audio[info->audio_cnt].conf_slot = call_med->strm.a.conf_slot; 
     1338        ++info->audio_cnt; 
     1339    } 
     1340 
     1341    if (info->audio_cnt) { 
     1342        info->media_status = info->audio[0].media_status; 
     1343        info->media_dir = info->audio[0].media_dir; 
     1344    } 
    13361345 
    13371346    /* conference slot number */ 
    1338     info->conf_slot = call->conf_slot; 
     1347    info->conf_slot = call->media[call->audio_idx].strm.a.conf_slot; 
    13391348 
    13401349    /* calculate duration */ 
     
    19601969        return status; 
    19611970 
    1962     if (!call->session) { 
     1971    if (!pjsua_call_has_media(call_id)) { 
    19631972        PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 
    19641973        pjsip_dlg_dec_lock(dlg); 
     
    19661975    } 
    19671976 
    1968     status = pjmedia_session_dial_dtmf( call->session, 0, digits); 
     1977    status = pjmedia_stream_dial_dtmf( 
     1978                call->media[call->audio_idx].strm.a.stream, digits); 
    19691979 
    19701980    pjsip_dlg_dec_lock(dlg); 
     
    21912201    char *p = buf, *end = buf+maxlen; 
    21922202    int len; 
    2193     pjmedia_session_info info; 
    2194     pjmedia_session *session = call->session; 
    2195     pjmedia_transport_info tp_info; 
    2196  
    2197     pjmedia_transport_info_init(&tp_info); 
    2198  
    2199     pjmedia_transport_get_info(call->med_tp, &tp_info); 
    2200     pjmedia_session_get_info(session, &info); 
    2201  
    2202     for (i=0; i<info.stream_cnt; ++i) { 
     2203 
     2204    for (i=0; i<call->med_cnt; ++i) { 
     2205        pjsua_call_media *call_med = &call->media[i]; 
     2206        pjmedia_stream_info info; 
     2207        pjmedia_stream *stream = call_med->strm.a.stream; 
     2208        pjmedia_transport_info tp_info; 
    22032209        pjmedia_rtcp_stat stat; 
    22042210        char rem_addr_buf[80]; 
     
    22092215        pj_time_val media_duration, now; 
    22102216 
    2211         pjmedia_session_get_stream_stat(session, i, &stat); 
     2217        /* Check if the stream is deactivated */ 
     2218        if (call_med->tp == NULL || stream == NULL) { 
     2219            const char *media_type_str; 
     2220 
     2221            switch (call_med->type) { 
     2222            case PJMEDIA_TYPE_AUDIO: 
     2223                media_type_str = "audio"; 
     2224                break; 
     2225            case PJMEDIA_TYPE_VIDEO: 
     2226                media_type_str = "video"; 
     2227                break; 
     2228            case PJMEDIA_TYPE_APPLICATION: 
     2229                media_type_str = "application"; 
     2230                break; 
     2231            default: 
     2232                media_type_str = "unknown"; 
     2233                break; 
     2234            } 
     2235            len = pj_ansi_snprintf(p, end-p, 
     2236                      "%s  #%d m=%s deactivated\n", 
     2237                      indent, i, media_type_str); 
     2238            if (len < 1 || len > end-p) { 
     2239                *p = '\0'; 
     2240                return; 
     2241            } 
     2242 
     2243            p += len; 
     2244            continue; 
     2245        } 
     2246 
     2247        pjmedia_transport_info_init(&tp_info); 
     2248        pjmedia_transport_get_info(call_med->tp, &tp_info); 
     2249 
     2250        pjmedia_stream_get_info(stream, &info); 
     2251        pjmedia_stream_get_stat(stream, &stat); 
     2252 
    22122253        // rem_addr will contain actual address of RTP originator, instead of 
    22132254        // remote RTP address specified by stream which is fetched from the SDP. 
     
    22232264        } 
    22242265 
    2225         if (call->media_dir == PJMEDIA_DIR_NONE) { 
     2266        if (call_med->dir == PJMEDIA_DIR_NONE) { 
    22262267            /* To handle when the stream that is currently being paused 
    22272268             * (http://trac.pjsip.org/repos/ticket/1079) 
    22282269             */ 
    22292270            dir = "inactive"; 
    2230         } else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING) 
     2271        } else if (info.dir == PJMEDIA_DIR_ENCODING) 
    22312272            dir = "sendonly"; 
    2232         else if (info.stream_info[i].dir == PJMEDIA_DIR_DECODING) 
     2273        else if (info.dir == PJMEDIA_DIR_DECODING) 
    22332274            dir = "recvonly"; 
    2234         else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING) 
     2275        else if (info.dir == PJMEDIA_DIR_ENCODING_DECODING) 
    22352276            dir = "sendrecv"; 
    22362277        else 
     
    22382279 
    22392280         
    2240         len = pj_ansi_snprintf(buf, end-p,  
     2281        len = pj_ansi_snprintf(p, end-p, 
    22412282                  "%s  #%d %.*s @%dKHz, %s, peer=%s", 
    22422283                  indent, i, 
    2243                   (int)info.stream_info[i].fmt.encoding_name.slen, 
    2244                   info.stream_info[i].fmt.encoding_name.ptr, 
    2245                   info.stream_info[i].fmt.clock_rate / 1000, 
     2284                  (int)info.fmt.encoding_name.slen, 
     2285                  info.fmt.encoding_name.ptr, 
     2286                  info.fmt.clock_rate / 1000, 
    22462287                  dir, 
    22472288                  rem_addr); 
     
    22942335#endif 
    22952336               "%s", 
    2296                indent, info.stream_info[i].fmt.pt, 
     2337               indent, info.fmt.pt, 
    22972338               last_update, 
    22982339               indent, 
     
    23712412               "%s        jitter     : %7.3f %7.3f %7.3f %7.3f %7.3f%s", 
    23722413               indent, 
    2373                info.stream_info[i].tx_pt, 
    2374                info.stream_info[i].param->info.frm_ptime * 
    2375                 info.stream_info[i].param->setting.frm_per_pkt, 
     2414               info.tx_pt, 
     2415               info.param->info.frm_ptime * info.param->setting.frm_per_pkt, 
    23762416               last_update, 
    23772417 
     
    24162456 
    24172457        len = pj_ansi_snprintf(p, end-p, 
    2418                "%s    RTT msec       : %7.3f %7.3f %7.3f %7.3f %7.3f",  
     2458               "%s     RTT msec      : %7.3f %7.3f %7.3f %7.3f %7.3f", 
    24192459               indent, 
    24202460               stat.rtt.min / 1000.0, 
     
    24712511            } 
    24722512 
    2473             clock_rate = info.stream_info[i].fmt.clock_rate; 
     2513            clock_rate = info.fmt.clock_rate; 
    24742514 
    24752515            len = pj_ansi_snprintf(p, end-p, "\n%s  Extended reports:", indent); 
     
    29442984 
    29452985    /* Get and ICE SRTP status */ 
     2986#if DISABLED_FOR_TICKET_1185 
    29462987    pjmedia_transport_info_init(&tp_info); 
    2947     pjmedia_transport_get_info(call->med_tp, &tp_info); 
     2988    pjmedia_transport_get_info(call->tp, &tp_info); 
    29482989    if (tp_info.specific_info_cnt > 0) { 
    29492990        unsigned i; 
     
    29843025        } 
    29853026    } 
     3027#endif  /* DISABLED_FOR_TICKET_1185 */ 
    29863028 
    29873029    /* Dump session statistics */ 
    2988     if (with_media && call->session) 
     3030    if (with_media && pjsua_call_has_media(call_id)) 
    29893031        dump_media_session(indent, p, end-p, call); 
    29903032 
     
    30643106    const pjmedia_sdp_media *ref_m; 
    30653107    pjmedia_sdp_media *m; 
     3108    pjsua_call_media *call_med = &call->media[call->audio_idx]; 
    30663109    unsigned i, codec_cnt = 0; 
    30673110    pj_bool_t rem_can_update; 
     
    30983141 
    30993142    /* Verify if media is deactivated */ 
    3100     if (call->media_st == PJSUA_CALL_MEDIA_NONE || 
    3101         call->media_st == PJSUA_CALL_MEDIA_ERROR || 
    3102         call->media_dir == PJMEDIA_DIR_NONE) 
     3143    if (call_med->state == PJSUA_CALL_MEDIA_NONE || 
     3144        call_med->state == PJSUA_CALL_MEDIA_ERROR || 
     3145        call_med->dir == PJMEDIA_DIR_NONE) 
    31033146    { 
    31043147        return PJ_EINVALIDOP; 
     
    31903233    const pjmedia_sdp_media *rem_m, *loc_m; 
    31913234    unsigned codec_cnt=0, i; 
     3235    pjsua_call_media *call_med = &call->media[call->audio_idx]; 
    31923236    pj_time_val delay = {0, 0}; 
    31933237    const pj_str_t st_update = {"UPDATE", 6}; 
     
    32073251 
    32083252    /* Skip this if the media is inactive or error */ 
    3209     if (call->media_st == PJSUA_CALL_MEDIA_NONE || 
    3210         call->media_st == PJSUA_CALL_MEDIA_ERROR || 
    3211         call->media_dir == PJMEDIA_DIR_NONE) 
     3253    if (call_med->state == PJSUA_CALL_MEDIA_NONE || 
     3254        call_med->state == PJSUA_CALL_MEDIA_ERROR || 
     3255        call_med->dir == PJMEDIA_DIR_NONE) 
    32123256    { 
    32133257        return PJ_SUCCESS; 
     
    35253569 
    35263570    /* Add SDP in 488 status */ 
    3527     if (call && call->med_tp && tdata->msg->type==PJSIP_RESPONSE_MSG &&  
     3571#if DISABLED_FOR_TICKET_1185 
     3572    if (call && call->tp && tdata->msg->type==PJSIP_RESPONSE_MSG && 
    35283573        code==PJSIP_SC_NOT_ACCEPTABLE_HERE)  
    35293574    { 
     
    35403585        } 
    35413586    } 
     3587#endif 
    35423588 
    35433589    pjsip_inv_send_msg(inv, tdata); 
     
    36553701     */ 
    36563702    /* http://trac.pjsip.org/repos/ticket/880  
    3657        if (call->media_dir != PJMEDIA_DIR_ENCODING) { 
     3703       if (call->dir != PJMEDIA_DIR_ENCODING) { 
    36583704     */ 
    36593705    /* https://trac.pjsip.org/repos/ticket/1142: 
     
    36953741        pjmedia_sdp_media_remove_all_attr(m, "inactive"); 
    36963742 
    3697         if (call->media_dir & PJMEDIA_DIR_ENCODING) { 
     3743        if (call->media[call->audio_idx].dir & PJMEDIA_DIR_ENCODING) { 
    36983744            /* Add sendonly attribute */ 
    36993745            attr = pjmedia_sdp_attr_create(pool, "sendonly", NULL); 
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_core.c

    r3366 r3457  
    104104    cfg->force_lr = PJ_TRUE; 
    105105    cfg->enable_unsolicited_mwi = PJ_TRUE; 
    106 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    107106    cfg->use_srtp = PJSUA_DEFAULT_USE_SRTP; 
    108107    cfg->srtp_secure_signaling = PJSUA_DEFAULT_SRTP_SECURE_SIGNALING; 
    109 #endif 
    110108    cfg->hangup_forked_call = PJ_TRUE; 
    111109 
     
    177175    cfg->ka_interval = 15; 
    178176    cfg->ka_data = pj_str("\r\n"); 
    179 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
     177    cfg->max_audio_cnt = 1; 
     178    pjsua_transport_config_default(&cfg->rtp_cfg); 
    180179    cfg->use_srtp = pjsua_var.ua_cfg.use_srtp; 
    181180    cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling; 
    182181    cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer; 
    183 #endif 
    184182    cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL; 
    185183    cfg->contact_rewrite_method = PJSUA_CONTACT_REWRITE_METHOD; 
     
    224222} 
    225223 
    226  
    227224/***************************************************************************** 
    228225 * This is a very simple PJSIP module, whose sole purpose is to display 
     
    379376 
    380377    /* Get media socket info, make sure transport is ready */ 
     378#if DISABLED_FOR_TICKET_1185 
    381379    if (pjsua_var.calls[0].med_tp) { 
    382380        pjmedia_transport_info_init(&tpinfo); 
     
    390388        } 
    391389    } 
    392  
    393     /* Send response statelessly */ 
     390#endif 
     391 
     392    /* Send response */ 
    394393    pjsip_get_response_addr(tdata->pool, rdata, &res_addr); 
    395394    status = pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, tdata, NULL, NULL); 
     
    660659    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    661660 
     661    pjsua_set_state(PJSUA_STATE_CREATED); 
    662662 
    663663    return PJ_SUCCESS; 
     
    919919                         pj_get_version(), PJ_OS_NAME)); 
    920920 
     921    pjsua_set_state(PJSUA_STATE_INIT); 
     922 
    921923    return PJ_SUCCESS; 
    922924 
     
    12761278    int i;  /* Must be signed */ 
    12771279 
     1280    if (pjsua_var.state > PJSUA_STATE_NULL && 
     1281        pjsua_var.state < PJSUA_STATE_CLOSING) 
     1282    { 
     1283        pjsua_set_state(PJSUA_STATE_CLOSING); 
     1284    } 
     1285 
    12781286    /* Signal threads to quit: */ 
    12791287    pjsua_var.thread_quit_flag = 1; 
     
    14531461    pj_bzero(&pjsua_var, sizeof(pjsua_var)); 
    14541462 
     1463    pjsua_set_state(PJSUA_STATE_NULL); 
     1464 
    14551465    /* Done. */ 
    14561466    return PJ_SUCCESS; 
    14571467} 
    14581468 
     1469void pjsua_set_state(pjsua_state new_state) 
     1470{ 
     1471    const char *state_name[] = { 
     1472        "NULL", 
     1473        "CREATED", 
     1474        "INIT", 
     1475        "STARTING", 
     1476        "RUNNING", 
     1477        "CLOSING" 
     1478    }; 
     1479    pjsua_state old_state = pjsua_var.state; 
     1480 
     1481    pjsua_var.state = new_state; 
     1482    PJ_LOG(4,(THIS_FILE, "PJSUA state changed: %s --> %s", 
     1483              state_name[old_state], state_name[new_state])); 
     1484} 
     1485 
     1486/* Get state */ 
     1487PJ_DEF(pjsua_state) pjsua_get_state(void) 
     1488{ 
     1489    return pjsua_var.state; 
     1490} 
    14591491 
    14601492/** 
     
    14691501    pj_status_t status; 
    14701502 
     1503    pjsua_set_state(PJSUA_STATE_STARTING); 
     1504 
    14711505    status = pjsua_call_subsys_start(); 
    14721506    if (status != PJ_SUCCESS) 
     
    14801514    if (status != PJ_SUCCESS) 
    14811515        return status; 
     1516 
     1517    pjsua_set_state(PJSUA_STATE_RUNNING); 
    14821518 
    14831519    return PJ_SUCCESS; 
     
    25642600 
    25652601    PJ_LOG(3,(THIS_FILE, "Dumping media transports:")); 
     2602#if DISABLED_FOR_TICKET_1185 
    25662603    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    25672604        pjsua_call *call = &pjsua_var.calls[i]; 
     
    25802617                                    sizeof(addr_buf), 3))); 
    25812618    } 
     2619#endif 
    25822620 
    25832621    pjsip_tsx_layer_dump(detail); 
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c

    r3392 r3457  
    275275#endif  /* PJMEDIA_HAS_L16_CODEC */ 
    276276 
     277#if PJMEDIA_HAS_VIDEO 
     278    status = pjmedia_video_format_mgr_create(pjsua_var.pool, 64, 0, NULL); 
     279    if (status != PJ_SUCCESS) { 
     280        pjsua_perror(THIS_FILE, "Error creating PJMEDIA video format manager", 
     281                     status); 
     282        return status; 
     283    } 
     284 
     285    status = pjmedia_converter_mgr_create(pjsua_var.pool, NULL); 
     286    if (status != PJ_SUCCESS) { 
     287        pjsua_perror(THIS_FILE, "Error creating PJMEDIA converter manager", 
     288                     status); 
     289        return status; 
     290    } 
     291 
     292    status = pjmedia_vid_codec_mgr_create(pjsua_var.pool, NULL); 
     293    if (status != PJ_SUCCESS) { 
     294        pjsua_perror(THIS_FILE, "Error creating PJMEDIA video codec manager", 
     295                     status); 
     296        return status; 
     297    } 
     298 
     299    status = pjmedia_vid_subsys_init(&pjsua_var.cp.factory); 
     300    if (status != PJ_SUCCESS) { 
     301        pjsua_perror(THIS_FILE, "Error creating PJMEDIA video subsystem", 
     302                     status); 
     303        return status; 
     304    } 
     305#endif 
     306 
     307#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_FFMPEG_CODEC 
     308    /* Init ffmpeg video codecs */ 
     309    status = pjmedia_codec_ffmpeg_init(NULL, &pjsua_var.cp.factory); 
     310    if (status != PJ_SUCCESS) { 
     311        pjsua_perror(THIS_FILE, "Error initializing ffmpeg library", 
     312                     status); 
     313        return status; 
     314    } 
     315#endif 
    277316 
    278317    /* Save additional conference bridge parameters for future 
     
    339378 
    340379 
    341 /*  
    342  * Create RTP and RTCP socket pair, and possibly resolve their public 
    343  * address via STUN. 
    344  */ 
    345 static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, 
    346                                         pjmedia_sock_info *skinfo) 
    347 { 
    348     enum {  
    349         RTP_RETRY = 100 
    350     }; 
    351     int i; 
    352     pj_sockaddr_in bound_addr; 
    353     pj_sockaddr_in mapped_addr[2]; 
    354     pj_status_t status = PJ_SUCCESS; 
    355     char addr_buf[PJ_INET6_ADDRSTRLEN+2]; 
    356     pj_sock_t sock[2]; 
    357  
    358     /* Make sure STUN server resolution has completed */ 
    359     status = resolve_stun_server(PJ_TRUE); 
    360     if (status != PJ_SUCCESS) { 
    361         pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
    362         return status; 
    363     } 
    364  
    365     if (next_rtp_port == 0) 
    366         next_rtp_port = (pj_uint16_t)cfg->port; 
    367  
    368     for (i=0; i<2; ++i) 
    369         sock[i] = PJ_INVALID_SOCKET; 
    370  
    371     bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; 
    372     if (cfg->bound_addr.slen) { 
    373         status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr); 
    374         if (status != PJ_SUCCESS) { 
    375             pjsua_perror(THIS_FILE, "Unable to resolve transport bind address", 
    376                          status); 
    377             return status; 
    378         } 
    379     } 
    380  
    381     /* Loop retry to bind RTP and RTCP sockets. */ 
    382     for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) { 
    383  
    384         /* Create RTP socket. */ 
    385         status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]); 
    386         if (status != PJ_SUCCESS) { 
    387             pjsua_perror(THIS_FILE, "socket() error", status); 
    388             return status; 
    389         } 
    390  
    391         /* Apply QoS to RTP socket, if specified */ 
    392         status = pj_sock_apply_qos2(sock[0], cfg->qos_type,  
    393                                     &cfg->qos_params,  
    394                                     2, THIS_FILE, "RTP socket"); 
    395  
    396         /* Bind RTP socket */ 
    397         status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr),  
    398                                next_rtp_port); 
    399         if (status != PJ_SUCCESS) { 
    400             pj_sock_close(sock[0]);  
    401             sock[0] = PJ_INVALID_SOCKET; 
    402             continue; 
    403         } 
    404  
    405         /* Create RTCP socket. */ 
    406         status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]); 
    407         if (status != PJ_SUCCESS) { 
    408             pjsua_perror(THIS_FILE, "socket() error", status); 
    409             pj_sock_close(sock[0]); 
    410             return status; 
    411         } 
    412  
    413         /* Apply QoS to RTCP socket, if specified */ 
    414         status = pj_sock_apply_qos2(sock[1], cfg->qos_type,  
    415                                     &cfg->qos_params,  
    416                                     2, THIS_FILE, "RTCP socket"); 
    417  
    418         /* Bind RTCP socket */ 
    419         status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr),  
    420                                (pj_uint16_t)(next_rtp_port+1)); 
    421         if (status != PJ_SUCCESS) { 
    422             pj_sock_close(sock[0]);  
    423             sock[0] = PJ_INVALID_SOCKET; 
    424  
    425             pj_sock_close(sock[1]);  
    426             sock[1] = PJ_INVALID_SOCKET; 
    427             continue; 
    428         } 
    429  
    430         /* 
    431          * If we're configured to use STUN, then find out the mapped address, 
    432          * and make sure that the mapped RTCP port is adjacent with the RTP. 
    433          */ 
    434         if (pjsua_var.stun_srv.addr.sa_family != 0) { 
    435             char ip_addr[32]; 
    436             pj_str_t stun_srv; 
    437  
    438             pj_ansi_strcpy(ip_addr,  
    439                            pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 
    440             stun_srv = pj_str(ip_addr); 
    441  
    442             status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, 
    443                                            &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 
    444                                            &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 
    445                                            mapped_addr); 
    446             if (status != PJ_SUCCESS) { 
    447                 pjsua_perror(THIS_FILE, "STUN resolve error", status); 
    448                 goto on_error; 
    449             } 
    450  
    451 #if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT 
    452             if (pj_ntohs(mapped_addr[1].sin_port) ==  
    453                 pj_ntohs(mapped_addr[0].sin_port)+1) 
    454             { 
    455                 /* Success! */ 
    456                 break; 
    457             } 
    458  
    459             pj_sock_close(sock[0]);  
    460             sock[0] = PJ_INVALID_SOCKET; 
    461  
    462             pj_sock_close(sock[1]);  
    463             sock[1] = PJ_INVALID_SOCKET; 
    464 #else 
    465             if (pj_ntohs(mapped_addr[1].sin_port) !=  
    466                 pj_ntohs(mapped_addr[0].sin_port)+1) 
    467             { 
    468                 PJ_LOG(4,(THIS_FILE,  
    469                           "Note: STUN mapped RTCP port %d is not adjacent" 
    470                           " to RTP port %d", 
    471                           pj_ntohs(mapped_addr[1].sin_port), 
    472                           pj_ntohs(mapped_addr[0].sin_port))); 
    473             } 
    474             /* Success! */ 
    475             break; 
    476 #endif 
    477  
    478         } else if (cfg->public_addr.slen) { 
    479  
    480             status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr, 
    481                                          (pj_uint16_t)next_rtp_port); 
    482             if (status != PJ_SUCCESS) 
    483                 goto on_error; 
    484  
    485             status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr, 
    486                                          (pj_uint16_t)(next_rtp_port+1)); 
    487             if (status != PJ_SUCCESS) 
    488                 goto on_error; 
    489  
    490             break; 
    491  
    492         } else { 
    493  
    494             if (bound_addr.sin_addr.s_addr == 0) { 
    495                 pj_sockaddr addr; 
    496  
    497                 /* Get local IP address. */ 
    498                 status = pj_gethostip(pj_AF_INET(), &addr); 
    499                 if (status != PJ_SUCCESS) 
    500                     goto on_error; 
    501  
    502                 bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr; 
    503             } 
    504  
    505             for (i=0; i<2; ++i) { 
    506                 pj_sockaddr_in_init(&mapped_addr[i], NULL, 0); 
    507                 mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr; 
    508             } 
    509  
    510             mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port); 
    511             mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1)); 
    512             break; 
    513         } 
    514     } 
    515  
    516     if (sock[0] == PJ_INVALID_SOCKET) { 
    517         PJ_LOG(1,(THIS_FILE,  
    518                   "Unable to find appropriate RTP/RTCP ports combination")); 
    519         goto on_error; 
    520     } 
    521  
    522  
    523     skinfo->rtp_sock = sock[0]; 
    524     pj_memcpy(&skinfo->rtp_addr_name,  
    525               &mapped_addr[0], sizeof(pj_sockaddr_in)); 
    526  
    527     skinfo->rtcp_sock = sock[1]; 
    528     pj_memcpy(&skinfo->rtcp_addr_name,  
    529               &mapped_addr[1], sizeof(pj_sockaddr_in)); 
    530  
    531     PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s", 
    532               pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf, 
    533                                 sizeof(addr_buf), 3))); 
    534     PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s", 
    535               pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf, 
    536                                 sizeof(addr_buf), 3))); 
    537  
    538     next_rtp_port += 2; 
    539     return PJ_SUCCESS; 
    540  
    541 on_error: 
    542     for (i=0; i<2; ++i) { 
    543         if (sock[i] != PJ_INVALID_SOCKET) 
    544             pj_sock_close(sock[i]); 
    545     } 
    546     return status; 
    547 } 
    548  
    549380/* Check if sound device is idle. */ 
    550381static void check_snd_dev_idle() 
     
    579410     * there is no active call. 
    580411     */ 
    581     if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) &&  
     412    if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) && 
    582413        pjsua_var.snd_idle_timer.id == PJ_FALSE && 
    583414        pjmedia_conf_get_connect_count(pjsua_var.mconf) == 0 && 
     
    591422 
    592423        pjsua_var.snd_idle_timer.id = PJ_TRUE; 
    593         pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer,  
     424        pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer, 
    594425                                   &delay); 
    595426    } 
     
    605436    PJSUA_LOCK(); 
    606437    if (entry->id) { 
    607         PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds",  
     438        PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds", 
    608439                  pjsua_var.media_cfg.snd_auto_close_time)); 
    609440 
     
    623454    pj_status_t status; 
    624455 
     456#if DISABLED_FOR_TICKET_1185 
    625457    /* Create media for calls, if none is specified */ 
    626     if (pjsua_var.calls[0].med_tp == NULL) { 
     458    if (pjsua_var.calls[0].media[0].tp == NULL) { 
    627459        pjsua_transport_config transport_cfg; 
    628460 
     
    635467            return status; 
    636468    } 
    637  
    638     pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL,  
     469#endif 
     470 
     471    pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL, 
    639472                        &close_snd_timer_cb); 
    640473 
    641474    /* Perform NAT detection */ 
    642     pjsua_detect_nat_type(); 
     475    status = pjsua_detect_nat_type(); 
     476    if (status != PJ_SUCCESS) { 
     477        PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed")); 
     478    } 
    643479 
    644480    return PJ_SUCCESS; 
     
    685521    /* Close media transports */ 
    686522    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    687         if (pjsua_var.calls[i].med_tp_st != PJSUA_MED_TP_IDLE) { 
    688             pjsua_media_channel_deinit(i); 
    689         } 
    690         if (pjsua_var.calls[i].med_tp && pjsua_var.calls[i].med_tp_auto_del) { 
    691             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    692         } 
    693         pjsua_var.calls[i].med_tp = NULL; 
     523        unsigned strm_idx; 
     524        pjsua_call *call = &pjsua_var.calls[i]; 
     525        for (strm_idx=0; strm_idx<call->med_cnt; ++strm_idx) { 
     526            pjsua_call_media *call_med = &call->media[strm_idx]; 
     527            if (call_med->tp_st != PJSUA_MED_TP_IDLE) { 
     528                pjsua_media_channel_deinit(i); 
     529            } 
     530            if (call_med->tp && call_med->tp_auto_del) { 
     531                pjmedia_transport_close(call_med->tp); 
     532            } 
     533            call_med->tp = NULL; 
     534        } 
    694535    } 
    695536 
    696537    /* Destroy media endpoint. */ 
    697538    if (pjsua_var.med_endpt) { 
     539 
     540        /* Videodev */ 
     541#       if PJMEDIA_HAS_VIDEO 
     542            pjmedia_vid_subsys_shutdown(); 
     543#       endif 
     544 
     545        /* ffmpeg */ 
     546#       if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_FFMPEG_CODEC 
     547            pjmedia_codec_ffmpeg_deinit(); 
     548#       endif 
    698549 
    699550        /* Shutdown all codecs: */ 
     
    745596} 
    746597 
    747  
     598/* 
     599 * Create RTP and RTCP socket pair, and possibly resolve their public 
     600 * address via STUN. 
     601 */ 
     602static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, 
     603                                        pjmedia_sock_info *skinfo) 
     604{ 
     605    enum { 
     606        RTP_RETRY = 100 
     607    }; 
     608    int i; 
     609    pj_sockaddr_in bound_addr; 
     610    pj_sockaddr_in mapped_addr[2]; 
     611    pj_status_t status = PJ_SUCCESS; 
     612    char addr_buf[PJ_INET6_ADDRSTRLEN+2]; 
     613    pj_sock_t sock[2]; 
     614 
     615    /* Make sure STUN server resolution has completed */ 
     616    status = resolve_stun_server(PJ_TRUE); 
     617    if (status != PJ_SUCCESS) { 
     618        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     619        return status; 
     620    } 
     621 
     622    if (next_rtp_port == 0) 
     623        next_rtp_port = (pj_uint16_t)cfg->port; 
     624 
     625    if (next_rtp_port == 0) 
     626        next_rtp_port = (pj_uint16_t)40000; 
     627 
     628    for (i=0; i<2; ++i) 
     629        sock[i] = PJ_INVALID_SOCKET; 
     630 
     631    bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; 
     632    if (cfg->bound_addr.slen) { 
     633        status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr); 
     634        if (status != PJ_SUCCESS) { 
     635            pjsua_perror(THIS_FILE, "Unable to resolve transport bind address", 
     636                         status); 
     637            return status; 
     638        } 
     639    } 
     640 
     641    /* Loop retry to bind RTP and RTCP sockets. */ 
     642    for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) { 
     643 
     644        /* Create RTP socket. */ 
     645        status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]); 
     646        if (status != PJ_SUCCESS) { 
     647            pjsua_perror(THIS_FILE, "socket() error", status); 
     648            return status; 
     649        } 
     650 
     651        /* Apply QoS to RTP socket, if specified */ 
     652        status = pj_sock_apply_qos2(sock[0], cfg->qos_type, 
     653                                    &cfg->qos_params, 
     654                                    2, THIS_FILE, "RTP socket"); 
     655 
     656        /* Bind RTP socket */ 
     657        status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr), 
     658                               next_rtp_port); 
     659        if (status != PJ_SUCCESS) { 
     660            pj_sock_close(sock[0]); 
     661            sock[0] = PJ_INVALID_SOCKET; 
     662            continue; 
     663        } 
     664 
     665        /* Create RTCP socket. */ 
     666        status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]); 
     667        if (status != PJ_SUCCESS) { 
     668            pjsua_perror(THIS_FILE, "socket() error", status); 
     669            pj_sock_close(sock[0]); 
     670            return status; 
     671        } 
     672 
     673        /* Apply QoS to RTCP socket, if specified */ 
     674        status = pj_sock_apply_qos2(sock[1], cfg->qos_type, 
     675                                    &cfg->qos_params, 
     676                                    2, THIS_FILE, "RTCP socket"); 
     677 
     678        /* Bind RTCP socket */ 
     679        status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr), 
     680                               (pj_uint16_t)(next_rtp_port+1)); 
     681        if (status != PJ_SUCCESS) { 
     682            pj_sock_close(sock[0]); 
     683            sock[0] = PJ_INVALID_SOCKET; 
     684 
     685            pj_sock_close(sock[1]); 
     686            sock[1] = PJ_INVALID_SOCKET; 
     687            continue; 
     688        } 
     689 
     690        /* 
     691         * If we're configured to use STUN, then find out the mapped address, 
     692         * and make sure that the mapped RTCP port is adjacent with the RTP. 
     693         */ 
     694        if (pjsua_var.stun_srv.addr.sa_family != 0) { 
     695            char ip_addr[32]; 
     696            pj_str_t stun_srv; 
     697 
     698            pj_ansi_strcpy(ip_addr, 
     699                           pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 
     700            stun_srv = pj_str(ip_addr); 
     701 
     702            status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, 
     703                                           &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 
     704                                           &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 
     705                                           mapped_addr); 
     706            if (status != PJ_SUCCESS) { 
     707                pjsua_perror(THIS_FILE, "STUN resolve error", status); 
     708                goto on_error; 
     709            } 
     710 
     711#if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT 
     712            if (pj_ntohs(mapped_addr[1].sin_port) == 
     713                pj_ntohs(mapped_addr[0].sin_port)+1) 
     714            { 
     715                /* Success! */ 
     716                break; 
     717            } 
     718 
     719            pj_sock_close(sock[0]); 
     720            sock[0] = PJ_INVALID_SOCKET; 
     721 
     722            pj_sock_close(sock[1]); 
     723            sock[1] = PJ_INVALID_SOCKET; 
     724#else 
     725            if (pj_ntohs(mapped_addr[1].sin_port) != 
     726                pj_ntohs(mapped_addr[0].sin_port)+1) 
     727            { 
     728                PJ_LOG(4,(THIS_FILE, 
     729                          "Note: STUN mapped RTCP port %d is not adjacent" 
     730                          " to RTP port %d", 
     731                          pj_ntohs(mapped_addr[1].sin_port), 
     732                          pj_ntohs(mapped_addr[0].sin_port))); 
     733            } 
     734            /* Success! */ 
     735            break; 
     736#endif 
     737 
     738        } else if (cfg->public_addr.slen) { 
     739 
     740            status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr, 
     741                                         (pj_uint16_t)next_rtp_port); 
     742            if (status != PJ_SUCCESS) 
     743                goto on_error; 
     744 
     745            status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr, 
     746                                         (pj_uint16_t)(next_rtp_port+1)); 
     747            if (status != PJ_SUCCESS) 
     748                goto on_error; 
     749 
     750            break; 
     751 
     752        } else { 
     753 
     754            if (bound_addr.sin_addr.s_addr == 0) { 
     755                pj_sockaddr addr; 
     756 
     757                /* Get local IP address. */ 
     758                status = pj_gethostip(pj_AF_INET(), &addr); 
     759                if (status != PJ_SUCCESS) 
     760                    goto on_error; 
     761 
     762                bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr; 
     763            } 
     764 
     765            for (i=0; i<2; ++i) { 
     766                pj_sockaddr_in_init(&mapped_addr[i], NULL, 0); 
     767                mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr; 
     768            } 
     769 
     770            mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port); 
     771            mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1)); 
     772            break; 
     773        } 
     774    } 
     775 
     776    if (sock[0] == PJ_INVALID_SOCKET) { 
     777        PJ_LOG(1,(THIS_FILE, 
     778                  "Unable to find appropriate RTP/RTCP ports combination")); 
     779        goto on_error; 
     780    } 
     781 
     782 
     783    skinfo->rtp_sock = sock[0]; 
     784    pj_memcpy(&skinfo->rtp_addr_name, 
     785              &mapped_addr[0], sizeof(pj_sockaddr_in)); 
     786 
     787    skinfo->rtcp_sock = sock[1]; 
     788    pj_memcpy(&skinfo->rtcp_addr_name, 
     789              &mapped_addr[1], sizeof(pj_sockaddr_in)); 
     790 
     791    PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s", 
     792              pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf, 
     793                                sizeof(addr_buf), 3))); 
     794    PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s", 
     795              pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf, 
     796                                sizeof(addr_buf), 3))); 
     797 
     798    next_rtp_port += 2; 
     799    return PJ_SUCCESS; 
     800 
     801on_error: 
     802    for (i=0; i<2; ++i) { 
     803        if (sock[i] != PJ_INVALID_SOCKET) 
     804            pj_sock_close(sock[i]); 
     805    } 
     806    return status; 
     807} 
     808 
     809/* Create normal UDP media transports */ 
     810static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg, 
     811                                              pjsua_call_media *call_med) 
     812{ 
     813    pjmedia_sock_info skinfo; 
     814    pj_status_t status; 
     815 
     816    status = create_rtp_rtcp_sock(cfg, &skinfo); 
     817    if (status != PJ_SUCCESS) { 
     818        pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 
     819                     status); 
     820        goto on_error; 
     821    } 
     822 
     823    status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL, 
     824                                          &skinfo, 0, &call_med->tp); 
     825    if (status != PJ_SUCCESS) { 
     826        pjsua_perror(THIS_FILE, "Unable to create media transport", 
     827                     status); 
     828        goto on_error; 
     829    } 
     830 
     831    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING, 
     832                                    pjsua_var.media_cfg.tx_drop_pct); 
     833 
     834    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING, 
     835                                    pjsua_var.media_cfg.rx_drop_pct); 
     836 
     837    return PJ_SUCCESS; 
     838 
     839on_error: 
     840    if (call_med->tp) 
     841        pjmedia_transport_close(call_med->tp); 
     842 
     843    return status; 
     844} 
     845 
     846#if DISABLED_FOR_TICKET_1185 
    748847/* Create normal UDP media transports */ 
    749848static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg) 
    750849{ 
    751850    unsigned i; 
    752     pjmedia_sock_info skinfo; 
    753851    pj_status_t status; 
    754852 
    755     /* Create each media transport */ 
    756     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    757  
    758         status = create_rtp_rtcp_sock(cfg, &skinfo); 
    759         if (status != PJ_SUCCESS) { 
    760             pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 
    761                          status); 
    762             goto on_error; 
    763         } 
    764  
    765         status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL, 
    766                                               &skinfo, 0, 
    767                                               &pjsua_var.calls[i].med_tp); 
    768         if (status != PJ_SUCCESS) { 
    769             pjsua_perror(THIS_FILE, "Unable to create media transport", 
    770                          status); 
    771             goto on_error; 
    772         } 
    773  
    774         pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 
    775                                         PJMEDIA_DIR_ENCODING, 
    776                                         pjsua_var.media_cfg.tx_drop_pct); 
    777  
    778         pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 
    779                                         PJMEDIA_DIR_DECODING, 
    780                                         pjsua_var.media_cfg.rx_drop_pct); 
    781  
     853    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 
     854        pjsua_call *call = &pjsua_var.calls[i]; 
     855        unsigned strm_idx; 
     856 
     857        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     858            pjsua_call_media *call_med = &call->media[strm_idx]; 
     859 
     860            status = create_udp_media_transport(cfg, &call_med->tp); 
     861            if (status != PJ_SUCCESS) 
     862                goto on_error; 
     863        } 
    782864    } 
    783865 
     
    785867 
    786868on_error: 
    787     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    788         if (pjsua_var.calls[i].med_tp != NULL) { 
    789             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    790             pjsua_var.calls[i].med_tp = NULL; 
    791         } 
    792     } 
    793  
     869    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 
     870        pjsua_call *call = &pjsua_var.calls[i]; 
     871        unsigned strm_idx; 
     872 
     873        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     874            pjsua_call_media *call_med = &call->media[strm_idx]; 
     875 
     876            if (call_med->tp) { 
     877                pjmedia_transport_close(call_med->tp); 
     878                call_med->tp = NULL; 
     879            } 
     880        } 
     881    } 
    794882    return status; 
    795883} 
    796  
     884#endif 
    797885 
    798886/* This callback is called when ICE negotiation completes */ 
     
    801889                            pj_status_t result) 
    802890{ 
    803     unsigned id; 
    804     pj_bool_t found = PJ_FALSE; 
    805  
    806     /* Find call which has this media transport */ 
    807  
    808     PJSUA_LOCK(); 
    809  
    810     for (id=0; id<pjsua_var.ua_cfg.max_calls; ++id) { 
    811         if (pjsua_var.calls[id].med_tp == tp || 
    812             pjsua_var.calls[id].med_orig == tp)  
    813         { 
    814             found = PJ_TRUE; 
    815             break; 
    816         } 
    817     } 
    818  
    819     PJSUA_UNLOCK(); 
    820  
    821     if (!found) 
     891    pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data; 
     892 
     893    if (!call_med) 
    822894        return; 
    823895 
    824896    switch (op) { 
    825897    case PJ_ICE_STRANS_OP_INIT: 
    826         pjsua_var.calls[id].med_tp_ready = result; 
     898        call_med->tp_ready = result; 
    827899        break; 
    828900    case PJ_ICE_STRANS_OP_NEGOTIATION: 
    829901        if (result != PJ_SUCCESS) { 
    830             pjsua_var.calls[id].media_st = PJSUA_CALL_MEDIA_ERROR; 
    831             pjsua_var.calls[id].media_dir = PJMEDIA_DIR_NONE; 
    832  
    833             if (pjsua_var.ua_cfg.cb.on_call_media_state) { 
    834                 pjsua_var.ua_cfg.cb.on_call_media_state(id); 
     902            call_med->state = PJSUA_CALL_MEDIA_ERROR; 
     903            call_med->dir = PJMEDIA_DIR_NONE; 
     904 
     905            if (call_med->call && pjsua_var.ua_cfg.cb.on_call_media_state) { 
     906                pjsua_var.ua_cfg.cb.on_call_media_state(call_med->call->index); 
    835907            } 
    836         } else { 
     908        } else if (call_med->call) { 
    837909            /* Send UPDATE if default transport address is different than 
    838910             * what was advertised (ticket #881) 
     
    854926            if (ii && ii->role==PJ_ICE_SESS_ROLE_CONTROLLING && 
    855927                pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name, 
    856                                 &pjsua_var.calls[id].med_rtp_addr)) 
     928                                &call_med->rtp_addr)) 
    857929            { 
    858930                pj_bool_t use_update; 
     
    861933                pjsip_dialog *dlg; 
    862934 
    863                 dlg = pjsua_var.calls[id].inv->dlg; 
     935                dlg = call_med->call->inv->dlg; 
    864936                support_update = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_ALLOW, 
    865937                                                          NULL, &STR_UPDATE); 
     
    868940                PJ_LOG(4,(THIS_FILE,  
    869941                          "ICE default transport address has changed for " 
    870                           "call %d, sending %s", id, 
     942                          "call %d, sending %s", call_med->call->index, 
    871943                          (use_update ? "UPDATE" : "re-INVITE"))); 
    872944 
    873945                if (use_update) 
    874                     pjsua_call_update(id, 0, NULL); 
     946                    pjsua_call_update(call_med->call->index, 0, NULL); 
    875947                else 
    876                     pjsua_call_reinvite(id, 0, NULL); 
     948                    pjsua_call_reinvite(call_med->call->index, 0, NULL); 
    877949            } 
    878950        } 
     
    881953        if (result != PJ_SUCCESS) { 
    882954            PJ_PERROR(4,(THIS_FILE, result, 
    883                          "ICE keep alive failure for transport %d", id)); 
     955                         "ICE keep alive failure for transport %d:%d", 
     956                         call_med->call->index, call_med->idx)); 
    884957        } 
    885958        if (pjsua_var.ua_cfg.cb.on_ice_transport_error) { 
     959            pjsua_call_id id = call_med->call->index; 
    886960            (*pjsua_var.ua_cfg.cb.on_ice_transport_error)(id, op, result, 
    887961                                                          NULL); 
     
    919993 
    920994/* Create ICE media transports (when ice is enabled) */ 
    921 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 
     995static pj_status_t create_ice_media_transport( 
     996                                const pjsua_transport_config *cfg, 
     997                                pjsua_call_media *call_med) 
    922998{ 
    923999    char stunip[PJ_INET6_ADDRSTRLEN]; 
    9241000    pj_ice_strans_cfg ice_cfg; 
    925     unsigned i; 
     1001    pjmedia_ice_cb ice_cb; 
     1002    char name[32]; 
     1003    unsigned comp_cnt; 
    9261004    pj_status_t status; 
    9271005 
     
    9801058    } 
    9811059 
    982     /* Create each media transport */ 
    983     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    984         pjmedia_ice_cb ice_cb; 
    985         char name[32]; 
    986         unsigned comp_cnt; 
    987  
    988         pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb)); 
    989         ice_cb.on_ice_complete = &on_ice_complete; 
    990         pj_ansi_snprintf(name, sizeof(name), "icetp%02d", i); 
    991         pjsua_var.calls[i].med_tp_ready = PJ_EPENDING; 
    992  
    993         comp_cnt = 1; 
    994         if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) 
    995             ++comp_cnt; 
    996  
    997         status = pjmedia_ice_create(pjsua_var.med_endpt, name, comp_cnt, 
    998                                     &ice_cfg, &ice_cb, 
    999                                     &pjsua_var.calls[i].med_tp); 
    1000         if (status != PJ_SUCCESS) { 
    1001             pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 
    1002                          status); 
    1003             goto on_error; 
    1004         } 
    1005  
    1006         /* Wait until transport is initialized, or time out */ 
    1007         PJSUA_UNLOCK(); 
    1008         while (pjsua_var.calls[i].med_tp_ready == PJ_EPENDING) { 
    1009             pjsua_handle_events(100); 
    1010         } 
    1011         PJSUA_LOCK(); 
    1012         if (pjsua_var.calls[i].med_tp_ready != PJ_SUCCESS) { 
    1013             pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 
    1014                          pjsua_var.calls[i].med_tp_ready); 
    1015             status = pjsua_var.calls[i].med_tp_ready; 
    1016             goto on_error; 
    1017         } 
    1018  
    1019         pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 
    1020                                         PJMEDIA_DIR_ENCODING, 
    1021                                         pjsua_var.media_cfg.tx_drop_pct); 
    1022  
    1023         pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 
    1024                                         PJMEDIA_DIR_DECODING, 
    1025                                         pjsua_var.media_cfg.rx_drop_pct); 
    1026     } 
     1060    pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb)); 
     1061    ice_cb.on_ice_complete = &on_ice_complete; 
     1062    pj_ansi_snprintf(name, sizeof(name), "icetp%02d", call_med->idx); 
     1063    call_med->tp_ready = PJ_EPENDING; 
     1064 
     1065    comp_cnt = 1; 
     1066    if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) 
     1067        ++comp_cnt; 
     1068 
     1069    status = pjmedia_ice_create(pjsua_var.med_endpt, name, comp_cnt, 
     1070                                &ice_cfg, &ice_cb, &call_med->tp); 
     1071    if (status != PJ_SUCCESS) { 
     1072        pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 
     1073                     status); 
     1074        goto on_error; 
     1075    } 
     1076 
     1077    /* Wait until transport is initialized, or time out */ 
     1078    PJSUA_UNLOCK(); 
     1079    while (call_med->tp_ready == PJ_EPENDING) { 
     1080        pjsua_handle_events(100); 
     1081    } 
     1082    PJSUA_LOCK(); 
     1083    if (call_med->tp_ready != PJ_SUCCESS) { 
     1084        pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 
     1085                     call_med->tp_ready); 
     1086        status = call_med->tp_ready; 
     1087        goto on_error; 
     1088    } 
     1089 
     1090    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING, 
     1091                                    pjsua_var.media_cfg.tx_drop_pct); 
     1092 
     1093    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING, 
     1094                                    pjsua_var.media_cfg.rx_drop_pct); 
    10271095 
    10281096    return PJ_SUCCESS; 
    10291097 
    10301098on_error: 
    1031     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    1032         if (pjsua_var.calls[i].med_tp != NULL) { 
    1033             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    1034             pjsua_var.calls[i].med_tp = NULL; 
    1035         } 
     1099    if (call_med->tp != NULL) { 
     1100        pjmedia_transport_close(call_med->tp); 
     1101        call_med->tp = NULL; 
    10361102    } 
    10371103 
     
    10391105} 
    10401106 
    1041  
    1042 /* 
    1043  * Create UDP media transports for all the calls. This function creates 
     1107#if DISABLED_FOR_TICKET_1185 
     1108/* Create ICE media transports (when ice is enabled) */ 
     1109static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 
     1110{ 
     1111    unsigned i; 
     1112    pj_status_t status; 
     1113 
     1114    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 
     1115        pjsua_call *call = &pjsua_var.calls[i]; 
     1116        unsigned strm_idx; 
     1117 
     1118        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     1119            pjsua_call_media *call_med = &call->media[strm_idx]; 
     1120 
     1121            status = create_ice_media_transport(cfg, call_med); 
     1122            if (status != PJ_SUCCESS) 
     1123                goto on_error; 
     1124        } 
     1125    } 
     1126 
     1127    return PJ_SUCCESS; 
     1128 
     1129on_error: 
     1130    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 
     1131        pjsua_call *call = &pjsua_var.calls[i]; 
     1132        unsigned strm_idx; 
     1133 
     1134        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     1135            pjsua_call_media *call_med = &call->media[strm_idx]; 
     1136 
     1137            if (call_med->tp) { 
     1138                pjmedia_transport_close(call_med->tp); 
     1139                call_med->tp = NULL; 
     1140            } 
     1141        } 
     1142    } 
     1143    return status; 
     1144} 
     1145#endif 
     1146 
     1147#if DISABLED_FOR_TICKET_1185 
     1148/* 
     1149 * Create media transports for all the calls. This function creates 
    10441150 * one UDP media transport for each call. 
    10451151 */ 
     
    10591165    /* Delete existing media transports */ 
    10601166    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    1061         if (pjsua_var.calls[i].med_tp != NULL &&  
    1062             pjsua_var.calls[i].med_tp_auto_del)  
    1063         { 
    1064             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    1065             pjsua_var.calls[i].med_tp = NULL; 
    1066             pjsua_var.calls[i].med_orig = NULL; 
     1167        pjsua_call *call = &pjsua_var.calls[i]; 
     1168        unsigned strm_idx; 
     1169 
     1170        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     1171            pjsua_call_media *call_med = &call->media[strm_idx]; 
     1172 
     1173            if (call_med->tp && call_med->tp_auto_del) { 
     1174                pjmedia_transport_close(call_med->tp); 
     1175                call_med->tp = NULL; 
     1176                call_med->tp_orig = NULL; 
     1177            } 
    10671178        } 
    10681179    } 
     
    10801191    /* Set media transport auto_delete to True */ 
    10811192    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    1082         pjsua_var.calls[i].med_tp_auto_del = PJ_TRUE; 
     1193        pjsua_call *call = &pjsua_var.calls[i]; 
     1194        unsigned strm_idx; 
     1195 
     1196        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     1197            pjsua_call_media *call_med = &call->media[strm_idx]; 
     1198 
     1199            call_med->tp_auto_del = PJ_TRUE; 
     1200        } 
    10831201    } 
    10841202 
     
    11011219    /* Assign the media transports */ 
    11021220    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    1103         if (pjsua_var.calls[i].med_tp != NULL &&  
    1104             pjsua_var.calls[i].med_tp_auto_del)  
    1105         { 
    1106             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    1107         } 
    1108  
    1109         pjsua_var.calls[i].med_tp = tp[i].transport; 
    1110         pjsua_var.calls[i].med_tp_auto_del = auto_delete; 
     1221        pjsua_call *call = &pjsua_var.calls[i]; 
     1222        unsigned strm_idx; 
     1223 
     1224        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     1225            pjsua_call_media *call_med = &call->media[strm_idx]; 
     1226 
     1227            if (call_med->tp && call_med->tp_auto_del) { 
     1228                pjmedia_transport_close(call_med->tp); 
     1229                call_med->tp = NULL; 
     1230                call_med->tp_orig = NULL; 
     1231            } 
     1232        } 
     1233 
     1234        PJ_TODO(remove_pjsua_media_transports_attach); 
     1235 
     1236        call->media[0].tp = tp[i].transport; 
     1237        call->media[0].tp_auto_del = auto_delete; 
    11111238    } 
    11121239 
    11131240    return PJ_SUCCESS; 
    11141241} 
    1115  
    1116  
    1117 static int find_audio_index(const pjmedia_sdp_session *sdp,  
    1118                             pj_bool_t prefer_srtp) 
     1242#endif 
     1243 
     1244/* Go through the list of media in the SDP, find acceptable media, and 
     1245 * sort them based on the "quality" of the media, and store the indexes 
     1246 * in the specified array. Media with the best quality will be listed 
     1247 * first in the array. The quality factors considered currently is 
     1248 * encryption. 
     1249 */ 
     1250static void sort_media(const pjmedia_sdp_session *sdp, 
     1251                       const pj_str_t *type, 
     1252                       pjmedia_srtp_use use_srtp, 
     1253                       pj_uint8_t midx[], 
     1254                       unsigned *p_count) 
    11191255{ 
    11201256    unsigned i; 
    1121     int audio_idx = -1; 
    1122  
    1123     for (i=0; i<sdp->media_count; ++i) { 
     1257    unsigned count = 0; 
     1258    int score[PJSUA_MAX_CALL_MEDIA]; 
     1259 
     1260    pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA); 
     1261 
     1262    *p_count = 0; 
     1263    pj_bzero(score, sizeof(score)); 
     1264 
     1265    /* Score each media */ 
     1266    for (i=0; i<sdp->media_count && count<PJSUA_MAX_CALL_MEDIA; ++i) { 
    11241267        const pjmedia_sdp_media *m = sdp->media[i]; 
    11251268 
    1126         /* Skip if media is not audio */ 
    1127         if (pj_stricmp2(&m->desc.media, "audio") != 0) 
     1269        /* Skip different media */ 
     1270        if (pj_stricmp(&m->desc.media, type) != 0) { 
     1271            score[count++] = -22000; 
    11281272            continue; 
    1129  
    1130         /* Skip if media is disabled */ 
     1273        } 
     1274 
     1275        /* Supported transports */ 
     1276        if (pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) { 
     1277            switch (use_srtp) { 
     1278            case PJMEDIA_SRTP_MANDATORY: 
     1279            case PJMEDIA_SRTP_OPTIONAL: 
     1280                ++score[i]; 
     1281                break; 
     1282            case PJMEDIA_SRTP_DISABLED: 
     1283                --score[i]; 
     1284                break; 
     1285            } 
     1286        } else if (pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) { 
     1287            switch (use_srtp) { 
     1288            case PJMEDIA_SRTP_MANDATORY: 
     1289                --score[i]; 
     1290                break; 
     1291            case PJMEDIA_SRTP_OPTIONAL: 
     1292                /* No change in score */ 
     1293                break; 
     1294            case PJMEDIA_SRTP_DISABLED: 
     1295                ++score[i]; 
     1296                break; 
     1297            } 
     1298        } else { 
     1299            score[i] -= 10; 
     1300        } 
     1301 
     1302        /* Is media disabled? */ 
    11311303        if (m->desc.port == 0) 
    1132             continue; 
    1133  
    1134         /* Skip if transport is not supported */ 
    1135         if (pj_stricmp2(&m->desc.transport, "RTP/AVP") != 0 && 
    1136             pj_stricmp2(&m->desc.transport, "RTP/SAVP") != 0) 
    1137         { 
    1138             continue; 
    1139         } 
    1140  
    1141         if (audio_idx == -1) { 
    1142             audio_idx = i; 
     1304            score[i] -= 10; 
     1305 
     1306        /* Is media inactive? */ 
     1307        if (pjmedia_sdp_media_find_attr2(m, "inactive", NULL)) 
     1308            score[i] -= 10; 
     1309 
     1310        ++count; 
     1311    } 
     1312 
     1313    /* Created sorted list based on quality */ 
     1314    for (i=0; i<count; ++i) { 
     1315        unsigned j; 
     1316        int best = 0; 
     1317 
     1318        for (j=1; j<count; ++j) { 
     1319            if (score[j] > score[best]) 
     1320                best = j; 
     1321        } 
     1322        /* Don't put media with negative score, that media is unacceptable 
     1323         * for us. 
     1324         */ 
     1325        if (score[best] >= 0) { 
     1326            midx[*p_count] = (pj_uint8_t)best; 
     1327            (*p_count)++; 
     1328        } 
     1329 
     1330        score[best] = -22000; 
     1331 
     1332    } 
     1333} 
     1334 
     1335/* Initialize the media line */ 
     1336static pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, 
     1337                                         pjmedia_type type, 
     1338                                         const pjsua_transport_config *tcfg, 
     1339                                         int security_level, 
     1340                                         int *sip_err_code) 
     1341{ 
     1342    pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; 
     1343    pj_status_t status; 
     1344 
     1345    /* 
     1346     * Note: this function may be called when the media already exists 
     1347     * (e.g. in reinvites, updates, etc.) 
     1348     */ 
     1349    call_med->type = type; 
     1350 
     1351    /* Create the media transport for initial call. This is blocking for now */ 
     1352    if (call_med->tp == NULL) { 
     1353        if (pjsua_var.media_cfg.enable_ice) { 
     1354            status = create_ice_media_transport(tcfg, call_med); 
    11431355        } else { 
    1144             /* We've found multiple candidates. This could happen 
    1145              * e.g. when remote is offering both RTP/SAVP and RTP/AVP, 
    1146              * or when remote for some reason offers two audio. 
    1147              */ 
    1148  
    1149             if (prefer_srtp && 
    1150                 pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) 
    1151             { 
    1152                 /* Prefer RTP/SAVP when our media transport is SRTP */ 
    1153                 audio_idx = i; 
    1154                 break; 
    1155             } else if (!prefer_srtp && 
    1156                        pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) 
    1157             { 
    1158                 /* Prefer RTP/AVP when our media transport is NOT SRTP */ 
    1159                 audio_idx = i; 
     1356            status = create_udp_media_transport(tcfg, call_med); 
     1357        } 
     1358 
     1359        if (status != PJ_SUCCESS) { 
     1360            PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport")); 
     1361            return status; 
     1362        } 
     1363    } 
     1364 
     1365#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
     1366    /* This function may be called when SRTP transport already exists 
     1367     * (e.g: in re-invite, update), don't need to destroy/re-create. 
     1368     */ 
     1369    if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) { 
     1370        pjmedia_srtp_setting srtp_opt; 
     1371        pjmedia_transport *srtp = NULL; 
     1372 
     1373        /* Check if SRTP requires secure signaling */ 
     1374        if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 
     1375            if (security_level < acc->cfg.srtp_secure_signaling) { 
     1376                if (sip_err_code) 
     1377                    *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
     1378                status = PJSIP_ESESSIONINSECURE; 
     1379                goto on_error; 
    11601380            } 
    11611381        } 
    1162     } 
    1163  
    1164     return audio_idx; 
    1165 } 
    1166  
     1382 
     1383        /* Always create SRTP adapter */ 
     1384        pjmedia_srtp_setting_default(&srtp_opt); 
     1385        srtp_opt.close_member_tp = PJ_FALSE; 
     1386        /* If media session has been ever established, let's use remote's 
     1387         * preference in SRTP usage policy, especially when it is stricter. 
     1388         */ 
     1389        if (call_med->rem_srtp_use > acc->cfg.use_srtp) 
     1390            srtp_opt.use = call_med->rem_srtp_use; 
     1391        else 
     1392            srtp_opt.use = acc->cfg.use_srtp; 
     1393 
     1394        status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 
     1395                                               call_med->tp, 
     1396                                               &srtp_opt, &srtp); 
     1397        if (status != PJ_SUCCESS) { 
     1398            if (sip_err_code) 
     1399                *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 
     1400            goto on_error; 
     1401        } 
     1402 
     1403        /* Set SRTP as current media transport */ 
     1404        call_med->tp_orig = call_med->tp; 
     1405        call_med->tp = srtp; 
     1406    } 
     1407#else 
     1408    call->tp_orig = call->tp; 
     1409    PJ_UNUSED_ARG(security_level); 
     1410#endif 
     1411 
     1412    return PJ_SUCCESS; 
     1413 
     1414on_error: 
     1415    if (call_med->tp) { 
     1416        pjmedia_transport_close(call_med->tp); 
     1417        call_med->tp = NULL; 
     1418    } 
     1419    return status; 
     1420} 
    11671421 
    11681422pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, 
     
    11731427                                     int *sip_err_code) 
    11741428{ 
     1429    const pj_str_t STR_AUDIO = { "audio", 5 }; 
     1430    const pj_str_t STR_VIDEO = { "video", 5 }; 
    11751431    pjsua_call *call = &pjsua_var.calls[call_id]; 
     1432    pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 
     1433    pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; 
     1434    unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); 
     1435    pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA]; 
     1436    unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx); 
     1437    pjmedia_type media_types[PJSUA_MAX_CALL_MEDIA]; 
     1438    unsigned mi; 
    11761439    pj_status_t status; 
    11771440 
    1178 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    1179     pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 
    1180     pjmedia_srtp_setting srtp_opt; 
    1181     pjmedia_transport *srtp = NULL; 
    1182 #endif 
    1183  
    11841441    PJ_UNUSED_ARG(role); 
    11851442 
     1443    if (pjsua_get_state() != PJSUA_STATE_RUNNING) 
     1444        return PJ_EBUSY; 
     1445 
     1446#if DISABLED_FOR_TICKET_1185 
    11861447    /* Return error if media transport has not been created yet 
    11871448     * (e.g. application is starting) 
    11881449     */ 
    1189     if (call->med_tp == NULL) { 
    1190         if (sip_err_code) 
    1191             *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 
    1192         return PJ_EBUSY; 
    1193     } 
    1194  
    1195 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    1196     /* This function may be called when SRTP transport already exists  
    1197      * (e.g: in re-invite, update), don't need to destroy/re-create. 
    1198      */ 
    1199     if (!call->med_orig || call->med_tp == call->med_orig) { 
    1200  
    1201         /* Check if SRTP requires secure signaling */ 
    1202         if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 
    1203             if (security_level < acc->cfg.srtp_secure_signaling) { 
    1204                 if (sip_err_code) 
    1205                     *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
    1206                 return PJSIP_ESESSIONINSECURE; 
    1207             } 
    1208         } 
    1209  
    1210         /* Always create SRTP adapter */ 
    1211         pjmedia_srtp_setting_default(&srtp_opt); 
    1212         srtp_opt.close_member_tp = PJ_FALSE; 
    1213         /* If media session has been ever established, let's use remote's  
    1214          * preference in SRTP usage policy, especially when it is stricter. 
    1215          */ 
    1216         if (call->rem_srtp_use > acc->cfg.use_srtp) 
    1217             srtp_opt.use = call->rem_srtp_use; 
    1218         else 
    1219             srtp_opt.use = acc->cfg.use_srtp; 
    1220  
    1221         status = pjmedia_transport_srtp_create(pjsua_var.med_endpt,  
    1222                                                call->med_tp, 
    1223                                                &srtp_opt, &srtp); 
    1224         if (status != PJ_SUCCESS) { 
    1225             if (sip_err_code) 
    1226                 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 
    1227             return status; 
    1228         } 
    1229  
    1230         /* Set SRTP as current media transport */ 
    1231         call->med_orig = call->med_tp; 
    1232         call->med_tp = srtp; 
    1233     } 
    1234 #else 
    1235     call->med_orig = call->med_tp; 
    1236     PJ_UNUSED_ARG(security_level); 
     1450    for (i=0; i<call->med_cnt; ++i) { 
     1451        if (call->media[i].tp == NULL) { 
     1452            return PJ_EBUSY; 
     1453        } 
     1454    } 
    12371455#endif 
    12381456 
    1239     /* Find out which media line in SDP that we support. If we are offerer, 
    1240      * audio will be initialized at index 0 in SDP.  
    1241      */ 
    1242     if (rem_sdp == NULL) { 
    1243         call->audio_idx = 0; 
    1244     }  
    1245     /* Otherwise find out the candidate audio media line in SDP */ 
    1246     else { 
    1247         pj_bool_t srtp_active; 
    1248  
    1249 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    1250         srtp_active = acc->cfg.use_srtp; 
    1251 #else 
    1252         srtp_active = PJ_FALSE; 
    1253 #endif 
    1254  
    1255         /* Media count must have been checked */ 
    1256         pj_assert(rem_sdp->media_count != 0); 
    1257  
    1258         call->audio_idx = find_audio_index(rem_sdp, srtp_active); 
    1259     } 
    1260  
    1261     /* Reject offer if we couldn't find a good m=audio line in offer */ 
    1262     if (call->audio_idx < 0) { 
     1457    if (rem_sdp) { 
     1458        sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, 
     1459                   maudidx, &maudcnt); 
     1460 
     1461        if (maudcnt==0) { 
     1462            /* Expecting audio in the offer */ 
     1463            if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 
     1464            pjsua_media_channel_deinit(call_id); 
     1465            return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 
     1466        } 
     1467 
     1468        sort_media(rem_sdp, &STR_VIDEO, acc->cfg.use_srtp, 
     1469                   mvididx, &mvidcnt); 
     1470        mvidcnt = (mvidcnt < acc->cfg.max_video_cnt) ? 
     1471                        mvidcnt : acc->cfg.max_video_cnt; 
     1472 
     1473    } else { 
     1474        maudcnt = acc->cfg.max_audio_cnt; 
     1475        for (mi=0; mi<maudcnt; ++mi) { 
     1476            maudidx[mi] = mi; 
     1477            media_types[mi] = PJMEDIA_TYPE_AUDIO; 
     1478        } 
     1479        mvidcnt = acc->cfg.max_video_cnt; 
     1480        for (mi=0; mi<mvidcnt; ++mi) { 
     1481            media_types[maudcnt + mi] = PJMEDIA_TYPE_VIDEO; 
     1482        } 
     1483    } 
     1484 
     1485    call->med_cnt = maudcnt + mvidcnt; 
     1486 
     1487    if (call->med_cnt == 0) { 
     1488        /* Expecting at least one media */ 
    12631489        if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 
    12641490        pjsua_media_channel_deinit(call_id); 
     
    12661492    } 
    12671493 
    1268     PJ_LOG(4,(THIS_FILE, "Media index %d selected for call %d", 
     1494    /* Initialize each media line */ 
     1495    for (mi=0; mi < call->med_cnt; ++mi) { 
     1496        pjsua_call_media *call_med = &call->media[mi]; 
     1497        pj_bool_t enabled = PJ_FALSE; 
     1498        pjmedia_type media_type = PJMEDIA_TYPE_NONE; 
     1499 
     1500        if (rem_sdp) { 
     1501            if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_AUDIO)) { 
     1502                media_type = PJMEDIA_TYPE_AUDIO; 
     1503                if (pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0]))) { 
     1504                    enabled = PJ_TRUE; 
     1505                } 
     1506            } 
     1507            else if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_VIDEO)) { 
     1508                media_type = PJMEDIA_TYPE_VIDEO; 
     1509                if (pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0]))) { 
     1510                    enabled = PJ_TRUE; 
     1511                } 
     1512            } 
     1513 
     1514        } else { 
     1515            enabled = PJ_TRUE; 
     1516            media_type = media_types[mi]; 
     1517        } 
     1518 
     1519        if (enabled) { 
     1520            status = pjsua_call_media_init(call_med, media_type, 
     1521                                           &acc->cfg.rtp_cfg, 
     1522                                           security_level, sip_err_code); 
     1523            if (status != PJ_SUCCESS) { 
     1524                pjsua_media_channel_deinit(call_id); 
     1525                return status; 
     1526            } 
     1527        } else { 
     1528            /* By convention, the media is inactive if transport is NULL */ 
     1529            if (call_med->tp) { 
     1530                pjmedia_transport_close(call_med->tp); 
     1531                call_med->tp = NULL; 
     1532            } 
     1533        } 
     1534    } 
     1535 
     1536    call->audio_idx = maudidx[0]; 
     1537 
     1538    PJ_LOG(4,(THIS_FILE, "Media index %d selected for audio call %d", 
    12691539              call->audio_idx, call->index)); 
    12701540 
    1271     /* Create the media transport */ 
    1272     status = pjmedia_transport_media_create(call->med_tp, tmp_pool, 0, 
    1273                                             rem_sdp, call->audio_idx); 
    1274     if (status != PJ_SUCCESS) { 
    1275         if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
    1276         pjsua_media_channel_deinit(call_id); 
    1277         return status; 
    1278     } 
    1279  
    1280     call->med_tp_st = PJSUA_MED_TP_INIT; 
     1541    /* Tell the media transport of a new offer/answer session */ 
     1542    for (mi=0; mi < call->med_cnt; ++mi) { 
     1543        pjsua_call_media *call_med = &call->media[mi]; 
     1544 
     1545        /* Note: tp may be NULL if this media line is inactive */ 
     1546        if (call_med->tp) { 
     1547            status = pjmedia_transport_media_create(call_med->tp, 
     1548                                                    tmp_pool, 0, 
     1549                                                    rem_sdp, mi); 
     1550            if (status != PJ_SUCCESS) { 
     1551                if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
     1552                pjsua_media_channel_deinit(call_id); 
     1553                return status; 
     1554            } 
     1555 
     1556            call_med->tp_st = PJSUA_MED_TP_INIT; 
     1557        } 
     1558    } 
     1559 
    12811560    return PJ_SUCCESS; 
    12821561} 
     
    12861565                                           const pjmedia_sdp_session *rem_sdp, 
    12871566                                           pjmedia_sdp_session **p_sdp, 
    1288                                            int *sip_status_code) 
    1289 { 
    1290     enum { MAX_MEDIA = 1 }; 
     1567                                           int *sip_err_code) 
     1568{ 
     1569    const pj_str_t STR_AUDIO = { "audio", 5 }; 
     1570    enum { MAX_MEDIA = PJSUA_MAX_CALL_MEDIA }; 
    12911571    pjmedia_sdp_session *sdp; 
    1292     pjmedia_transport_info tpinfo; 
     1572    pj_sockaddr origin; 
    12931573    pjsua_call *call = &pjsua_var.calls[call_id]; 
     1574    pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 
    12941575    pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL; 
     1576    unsigned mi; 
    12951577    pj_status_t status; 
    12961578 
    1297     /* Return error if media transport has not been created yet 
    1298      * (e.g. application is starting) 
     1579    if (pjsua_get_state() != PJSUA_STATE_RUNNING) 
     1580        return PJ_EBUSY; 
     1581 
     1582    if (rem_sdp) { 
     1583        pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; 
     1584        unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); 
     1585 
     1586        sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, 
     1587                   maudidx, &maudcnt); 
     1588 
     1589        if (maudcnt==0) { 
     1590            /* Expecting audio in the offer */ 
     1591            if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 
     1592            pjsua_media_channel_deinit(call_id); 
     1593            return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 
     1594        } 
     1595 
     1596        call->audio_idx = maudidx[0]; 
     1597    } else { 
     1598        /* Audio is first in our offer, by convention */ 
     1599        call->audio_idx = 0; 
     1600    } 
     1601 
     1602    /* Create media if it's not created. This could happen when call is 
     1603     * currently on-hold (with the old style hold) 
    12991604     */ 
    1300     if (call->med_tp == NULL) { 
    1301         return PJ_EBUSY; 
    1302     } 
    1303  
    1304     if (rem_sdp && rem_sdp->media_count != 0) { 
    1305         pj_bool_t srtp_active; 
    1306  
    1307 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    1308         srtp_active = pjsua_var.acc[call->acc_id].cfg.use_srtp; 
    1309 #else 
    1310         srtp_active = PJ_FALSE; 
    1311 #endif 
    1312  
    1313         call->audio_idx = find_audio_index(rem_sdp, srtp_active); 
    1314         if (call->audio_idx == -1) { 
    1315             /* No audio in the offer. We can't accept this */ 
    1316             PJ_LOG(4,(THIS_FILE, 
    1317                       "Unable to accept SDP offer without audio for call %d", 
    1318                       call_id)); 
    1319             return PJMEDIA_SDP_EINMEDIA; 
    1320         } 
    1321     } 
    1322  
    1323     /* Media index must have been determined before */ 
    1324     pj_assert(call->audio_idx != -1); 
    1325  
    1326     /* Create media if it's not created. This could happen when call is 
    1327      * currently on-hold 
    1328      */ 
    1329     if (call->med_tp_st == PJSUA_MED_TP_IDLE) { 
     1605    if (call->media[call->audio_idx].tp == NULL) { 
    13301606        pjsip_role_e role; 
    13311607        role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC); 
    13321608        status = pjsua_media_channel_init(call_id, role, call->secure_level,  
    1333                                           pool, rem_sdp, sip_status_code); 
     1609                                          pool, rem_sdp, sip_err_code); 
    13341610        if (status != PJ_SUCCESS) 
    13351611            return status; 
     
    13401616        sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg); 
    13411617 
    1342     /* Get media socket info */ 
    1343     pjmedia_transport_info_init(&tpinfo); 
    1344     pjmedia_transport_get_info(call->med_tp, &tpinfo); 
    1345  
    1346     /* Create SDP */ 
    1347     status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, MAX_MEDIA, 
    1348                                       &tpinfo.sock_info, &sdp); 
    1349     if (status != PJ_SUCCESS) { 
    1350         if (sip_status_code) *sip_status_code = 500; 
     1618    /* Get one address to use in the origin field */ 
     1619    pj_bzero(&origin, sizeof(origin)); 
     1620    for (mi=0; mi<call->med_cnt; ++mi) { 
     1621        pjmedia_transport_info tpinfo; 
     1622 
     1623        if (call->media[mi].tp == NULL) 
     1624            continue; 
     1625 
     1626        pjmedia_transport_info_init(&tpinfo); 
     1627        pjmedia_transport_get_info(call->media[mi].tp, &tpinfo); 
     1628        pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name); 
     1629        break; 
     1630    } 
     1631 
     1632    /* Create the base (blank) SDP */ 
     1633    status = pjmedia_endpt_create_base_sdp(pjsua_var.med_endpt, pool, NULL, 
     1634                                           &origin, &sdp); 
     1635    if (status != PJ_SUCCESS) 
    13511636        return status; 
    1352     } 
    1353  
    1354     /* If we're answering or updating the session with a new offer, 
    1355      * and the selected media is not the first media 
    1356      * in SDP, then fill in the unselected media with with zero port.  
    1357      * Otherwise we'll crash in transport_encode_sdp() because the media 
    1358      * lines are not aligned between offer and answer. 
    1359      */ 
    1360     if (call->audio_idx != 0 &&  
    1361         (rem_sdp || sdp_neg_state==PJMEDIA_SDP_NEG_STATE_DONE)) 
    1362     { 
    1363         unsigned i; 
    1364         const pjmedia_sdp_session *ref_sdp = rem_sdp; 
    1365  
    1366         if (!ref_sdp) { 
    1367             /* We are updating session with a new offer */ 
    1368             status = pjmedia_sdp_neg_get_active_local(call->inv->neg, 
    1369                                                       &ref_sdp); 
    1370             pj_assert(status == PJ_SUCCESS); 
    1371         } 
    1372  
    1373         for (i=0; i<ref_sdp->media_count; ++i) { 
    1374             const pjmedia_sdp_media *ref_m = ref_sdp->media[i]; 
    1375             pjmedia_sdp_media *m; 
    1376  
    1377             if ((int)i == call->audio_idx) 
    1378                 continue; 
    1379  
    1380             m = pjmedia_sdp_media_clone_deactivate(pool, ref_m); 
    1381             if (i==sdp->media_count) 
    1382                 sdp->media[sdp->media_count++] = m; 
    1383             else { 
    1384                 pj_array_insert(sdp->media, sizeof(sdp->media[0]), 
    1385                                 sdp->media_count, i, &m); 
    1386                 ++sdp->media_count; 
     1637 
     1638    /* Process each media line */ 
     1639    for (mi=0; mi<call->med_cnt; ++mi) { 
     1640        pjsua_call_media *call_med = &call->media[mi]; 
     1641        pjmedia_sdp_media *m = NULL; 
     1642        pjmedia_transport_info tpinfo; 
     1643 
     1644        if (call_med->tp == NULL) { 
     1645            /* 
     1646             * This media is deactivated. Just create a valid SDP with zero 
     1647             * port. 
     1648             */ 
     1649            m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); 
     1650            m->desc.transport = pj_str("RTP/AVP"); 
     1651            m->desc.fmt_count = 1; 
     1652            m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); 
     1653            m->conn->net_type = pj_str("IN"); 
     1654            m->conn->addr_type = pj_str("IP4"); 
     1655            m->conn->addr = pj_str("127.0.0.1"); 
     1656 
     1657            switch (call_med->type) { 
     1658            case PJMEDIA_TYPE_AUDIO: 
     1659                m->desc.media = pj_str("audio"); 
     1660                m->desc.fmt[0] = pj_str("0"); 
     1661                break; 
     1662            case PJMEDIA_TYPE_VIDEO: 
     1663                m->desc.media = pj_str("video"); 
     1664                m->desc.fmt[0] = pj_str("31"); 
     1665                break; 
     1666            default: 
     1667                if (rem_sdp && mi < rem_sdp->media_count) { 
     1668                    pj_strdup(pool, &m->desc.media, 
     1669                              &rem_sdp->media[mi]->desc.media); 
     1670                    pj_strdup(pool, &m->desc.fmt[0], 
     1671                              &rem_sdp->media[mi]->desc.fmt[0]); 
     1672                } else { 
     1673                    pj_assert(!"Invalid call_med media type"); 
     1674                    return PJ_EBUG; 
     1675                } 
    13871676            } 
     1677 
     1678            sdp->media[sdp->media_count++] = m; 
     1679            continue; 
     1680        } 
     1681 
     1682        /* Get transport address info */ 
     1683        pjmedia_transport_info_init(&tpinfo); 
     1684        pjmedia_transport_get_info(call_med->tp, &tpinfo); 
     1685 
     1686        /* Ask pjmedia endpoint to create SDP media line */ 
     1687        switch (call_med->type) { 
     1688        case PJMEDIA_TYPE_AUDIO: 
     1689            status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool, 
     1690                                                    &tpinfo.sock_info, 0, &m); 
     1691            break; 
     1692        case PJMEDIA_TYPE_VIDEO: 
     1693            status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool, 
     1694                                                    &tpinfo.sock_info, 0, &m); 
     1695            break; 
     1696        default: 
     1697            pj_assert(!"Invalid call_med media type"); 
     1698            return PJ_EBUG; 
     1699        } 
     1700 
     1701        if (status != PJ_SUCCESS) 
     1702            return status; 
     1703 
     1704        sdp->media[sdp->media_count++] = m; 
     1705 
     1706        /* Give to transport */ 
     1707        status = pjmedia_transport_encode_sdp(call_med->tp, pool, 
     1708                                              sdp, rem_sdp, mi); 
     1709        if (status != PJ_SUCCESS) { 
     1710            if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
     1711            return status; 
    13881712        } 
    13891713    } 
     
    14131737    } 
    14141738 
    1415     /* Give the SDP to media transport */ 
    1416     status = pjmedia_transport_encode_sdp(call->med_tp, pool, sdp, rem_sdp,  
    1417                                           call->audio_idx); 
    1418     if (status != PJ_SUCCESS) { 
    1419         if (sip_status_code) *sip_status_code = PJSIP_SC_NOT_ACCEPTABLE; 
    1420         return status; 
    1421     } 
    1422  
    1423 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
     1739 
     1740#if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    14241741    /* Check if SRTP is in optional mode and configured to use duplicated 
    14251742     * media, i.e: secured and unsecured version, in the SDP offer. 
     
    14341751            pjmedia_sdp_media *m = sdp->media[i]; 
    14351752 
    1436             /* Check if this media is unsecured but has SDP "crypto"  
     1753            /* Check if this media is unsecured but has SDP "crypto" 
    14371754             * attribute. 
    14381755             */ 
     
    14401757                pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL) 
    14411758            { 
    1442                 if (i == (unsigned)call->audio_idx &&  
     1759                if (i == (unsigned)call->audio_idx && 
    14431760                    sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE) 
    14441761                { 
     
    14631780                    /* Insert the new media before the unsecured media */ 
    14641781                    if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) { 
    1465                         pj_array_insert(sdp->media, sizeof(new_m),  
     1782                        pj_array_insert(sdp->media, sizeof(new_m), 
    14661783                                        sdp->media_count, i, &new_m); 
    14671784                        ++sdp->media_count; 
     
    14741791#endif 
    14751792 
    1476     /* Update currently advertised RTP source address */ 
    1477     pj_memcpy(&call->med_rtp_addr, &tpinfo.sock_info.rtp_addr_name,  
    1478               sizeof(pj_sockaddr)); 
    1479  
    14801793    *p_sdp = sdp; 
    14811794    return PJ_SUCCESS; 
     
    14861799{ 
    14871800    pjsua_call *call = &pjsua_var.calls[call_id]; 
    1488  
    1489     if (call->conf_slot != PJSUA_INVALID_ID) { 
    1490         if (pjsua_var.mconf) { 
    1491             pjsua_conf_remove_port(call->conf_slot); 
    1492         } 
    1493         call->conf_slot = PJSUA_INVALID_ID; 
    1494     } 
    1495  
    1496     if (call->session) { 
    1497         pjmedia_rtcp_stat stat; 
    1498  
    1499         if ((call->media_dir & PJMEDIA_DIR_ENCODING) && 
    1500             (pjmedia_session_get_stream_stat(call->session, 0, &stat)  
    1501              == PJ_SUCCESS)) 
     1801    unsigned mi; 
     1802 
     1803    for (mi=0; mi<call->med_cnt; ++mi) { 
     1804        pjsua_call_media *call_med = &call->media[mi]; 
     1805 
     1806        if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
     1807            pjmedia_stream *strm = call_med->strm.a.stream; 
     1808            pjmedia_rtcp_stat stat; 
     1809 
     1810            if (strm) { 
     1811                if (call_med->strm.a.conf_slot != PJSUA_INVALID_ID) { 
     1812                    if (pjsua_var.mconf) { 
     1813                        pjsua_conf_remove_port(call_med->strm.a.conf_slot); 
     1814                    } 
     1815                    call_med->strm.a.conf_slot = PJSUA_INVALID_ID; 
     1816                } 
     1817 
     1818                if ((call_med->dir & PJMEDIA_DIR_ENCODING) && 
     1819                    (pjmedia_stream_get_stat(strm, &stat) == PJ_SUCCESS)) 
     1820                { 
     1821                    /* Save RTP timestamp & sequence, so when media session is 
     1822                     * restarted, those values will be restored as the initial 
     1823                     * RTP timestamp & sequence of the new media session. So in 
     1824                     * the same call session, RTP timestamp and sequence are 
     1825                     * guaranteed to be contigue. 
     1826                     */ 
     1827                    call_med->rtp_tx_seq_ts_set = 1 | (1 << 1); 
     1828                    call_med->rtp_tx_seq = stat.rtp_tx_last_seq; 
     1829                    call_med->rtp_tx_ts = stat.rtp_tx_last_ts; 
     1830                } 
     1831 
     1832                if (pjsua_var.ua_cfg.cb.on_stream_destroyed) { 
     1833                    pjsua_var.ua_cfg.cb.on_stream_destroyed(call_id, strm, mi); 
     1834                } 
     1835 
     1836                pjmedia_stream_destroy(strm); 
     1837                call_med->strm.a.stream = NULL; 
     1838 
     1839                PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed", 
     1840                                     call_id, mi)); 
     1841            } 
     1842        } 
     1843        call_med->state = PJSUA_CALL_MEDIA_NONE; 
     1844    } 
     1845} 
     1846 
     1847pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id) 
     1848{ 
     1849    pjsua_call *call = &pjsua_var.calls[call_id]; 
     1850    unsigned mi; 
     1851 
     1852    stop_media_session(call_id); 
     1853 
     1854    for (mi=0; mi<call->med_cnt; ++mi) { 
     1855        pjsua_call_media *call_med = &call->media[mi]; 
     1856 
     1857        if (call_med->tp_st != PJSUA_MED_TP_IDLE) { 
     1858            pjmedia_transport_media_stop(call_med->tp); 
     1859            call_med->tp_st = PJSUA_MED_TP_IDLE; 
     1860        } 
     1861 
     1862        if (call_med->tp_orig && call_med->tp && 
     1863                call_med->tp != call_med->tp_orig) 
    15021864        { 
    1503             /* Save RTP timestamp & sequence, so when media session is  
    1504              * restarted, those values will be restored as the initial  
    1505              * RTP timestamp & sequence of the new media session. So in  
    1506              * the same call session, RTP timestamp and sequence are  
    1507              * guaranteed to be contigue. 
    1508              */ 
    1509             call->rtp_tx_seq_ts_set = 1 | (1 << 1); 
    1510             call->rtp_tx_seq = stat.rtp_tx_last_seq; 
    1511             call->rtp_tx_ts = stat.rtp_tx_last_ts; 
    1512         } 
    1513  
    1514         if (pjsua_var.ua_cfg.cb.on_stream_destroyed) { 
    1515             pjsua_var.ua_cfg.cb.on_stream_destroyed(call_id, call->session, 0); 
    1516         } 
    1517  
    1518         pjmedia_session_destroy(call->session); 
    1519         call->session = NULL; 
    1520  
    1521         PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed",  
    1522                              call_id)); 
    1523  
    1524     } 
    1525  
    1526     call->media_st = PJSUA_CALL_MEDIA_NONE; 
    1527 } 
    1528  
    1529 pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id) 
    1530 { 
    1531     pjsua_call *call = &pjsua_var.calls[call_id]; 
    1532  
    1533     stop_media_session(call_id); 
    1534  
    1535     if (call->med_tp_st != PJSUA_MED_TP_IDLE) { 
    1536         pjmedia_transport_media_stop(call->med_tp); 
    1537         call->med_tp_st = PJSUA_MED_TP_IDLE; 
    1538     } 
    1539  
    1540     if (call->med_orig && call->med_tp && call->med_tp != call->med_orig) { 
    1541         pjmedia_transport_close(call->med_tp); 
    1542         call->med_tp = call->med_orig; 
     1865            pjmedia_transport_close(call_med->tp); 
     1866            call_med->tp = call_med->tp_orig; 
     1867        } 
    15431868    } 
    15441869 
     
    15701895 
    15711896 
    1572 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 
    1573                                        const pjmedia_sdp_session *local_sdp, 
    1574                                        const pjmedia_sdp_session *remote_sdp) 
    1575 { 
    1576     int prev_media_st = 0; 
    1577     pjsua_call *call = &pjsua_var.calls[call_id]; 
    1578     pjmedia_session_info sess_info; 
    1579     pjmedia_stream_info *si = NULL; 
     1897static pj_status_t audio_channel_update(pjsua_call_media *call_med, 
     1898                                        pj_pool_t *tmp_pool, 
     1899                                        const pjmedia_sdp_session *local_sdp, 
     1900                                        const pjmedia_sdp_session *remote_sdp) 
     1901{ 
     1902    pjsua_call *call = call_med->call; 
     1903    pjmedia_stream_info the_si, *si = &the_si; 
    15801904    pjmedia_port *media_port; 
     1905    unsigned strm_idx = call_med->idx; 
    15811906    pj_status_t status; 
    1582  
    1583     if (!pjsua_var.med_endpt) { 
    1584         /* We're being shutdown */ 
    1585         return PJ_EBUSY; 
    1586     } 
    1587  
    1588     /* Destroy existing media session, if any. */ 
    1589     prev_media_st = call->media_st; 
    1590     stop_media_session(call->index); 
    1591  
    1592     /* Create media session info based on SDP parameters.  
    1593      */     
    1594     status = pjmedia_session_info_from_sdp( call->inv->pool_prov,  
    1595                                             pjsua_var.med_endpt,  
    1596                                             PJMEDIA_MAX_SDP_MEDIA, &sess_info, 
    1597                                             local_sdp, remote_sdp); 
     1907     
     1908    status = pjmedia_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt, 
     1909                                          local_sdp, remote_sdp, strm_idx); 
    15981910    if (status != PJ_SUCCESS) 
    15991911        return status; 
    16001912 
    1601     /* Update audio index from the negotiated SDP */ 
    1602     call->audio_idx = find_audio_index(local_sdp, PJ_TRUE); 
    1603  
    1604     /* Find which session is audio */ 
    1605     PJ_ASSERT_RETURN(call->audio_idx != -1, PJ_EBUG); 
    1606     PJ_ASSERT_RETURN(call->audio_idx < (int)sess_info.stream_cnt, PJ_EBUG); 
    1607     si = &sess_info.stream_info[call->audio_idx]; 
    1608      
    1609     /* Reset session info with only one media stream */ 
    1610     sess_info.stream_cnt = 1; 
    1611     if (si != &sess_info.stream_info[0]) { 
    1612         pj_memcpy(&sess_info.stream_info[0], si, sizeof(pjmedia_stream_info)); 
    1613         si = &sess_info.stream_info[0]; 
    1614     } 
    1615  
    16161913    /* Check if no media is active */ 
    1617     if (sess_info.stream_cnt == 0 || si->dir == PJMEDIA_DIR_NONE) 
    1618     { 
     1914    if (si->dir == PJMEDIA_DIR_NONE) { 
    16191915        /* Call media state */ 
    1620         call->media_st = PJSUA_CALL_MEDIA_NONE; 
     1916        call_med->state = PJSUA_CALL_MEDIA_NONE; 
    16211917 
    16221918        /* Call media direction */ 
    1623         call->media_dir = PJMEDIA_DIR_NONE; 
    1624  
    1625         /* Don't stop transport because we need to transmit keep-alives, and 
    1626          * also to prevent restarting ICE negotiation. See 
    1627          *  http://trac.pjsip.org/repos/ticket/1094 
    1628          */ 
    1629 #if 0 
    1630         /* Shutdown transport's session */ 
    1631         pjmedia_transport_media_stop(call->med_tp); 
    1632         call->med_tp_st = PJSUA_MED_TP_IDLE; 
    1633  
    1634         /* No need because we need keepalive? */ 
    1635  
    1636         /* Close upper entry of transport stack */ 
    1637         if (call->med_orig && (call->med_tp != call->med_orig)) { 
    1638             pjmedia_transport_close(call->med_tp); 
    1639             call->med_tp = call->med_orig; 
    1640         } 
    1641 #endif 
     1919        call_med->dir = PJMEDIA_DIR_NONE; 
    16421920 
    16431921    } else { 
     
    16451923 
    16461924        /* Start/restart media transport */ 
    1647         status = pjmedia_transport_media_start(call->med_tp,  
    1648                                                call->inv->pool_prov, 
    1649                                                local_sdp, remote_sdp, 
    1650                                                call->audio_idx); 
     1925        status = pjmedia_transport_media_start(call_med->tp, 
     1926                                               tmp_pool, local_sdp, 
     1927                                               remote_sdp, strm_idx); 
    16511928        if (status != PJ_SUCCESS) 
    16521929            return status; 
    16531930 
    1654         call->med_tp_st = PJSUA_MED_TP_RUNNING; 
     1931        call_med->tp_st = PJSUA_MED_TP_RUNNING; 
    16551932 
    16561933        /* Get remote SRTP usage policy */ 
    16571934        pjmedia_transport_info_init(&tp_info); 
    1658         pjmedia_transport_get_info(call->med_tp, &tp_info); 
     1935        pjmedia_transport_get_info(call_med->tp, &tp_info); 
    16591936        if (tp_info.specific_info_cnt > 0) { 
    16601937            unsigned i; 
     
    16651942                                (pjmedia_srtp_info*) tp_info.spc_info[i].buffer; 
    16661943 
    1667                     call->rem_srtp_use = srtp_info->peer_use; 
     1944                    call_med->rem_srtp_use = srtp_info->peer_use; 
    16681945                    break; 
    16691946                } 
     
    16941971 
    16951972        /* Set SSRC */ 
    1696         si->ssrc = call->ssrc; 
     1973        si->ssrc = call_med->ssrc; 
    16971974 
    16981975        /* Set RTP timestamp & sequence, normally these value are intialized 
     
    17011978         * contigue. 
    17021979         */ 
    1703         si->rtp_ts = call->rtp_tx_ts; 
    1704         si->rtp_seq = call->rtp_tx_seq; 
    1705         si->rtp_seq_ts_set = call->rtp_tx_seq_ts_set; 
     1980        si->rtp_ts = call_med->rtp_tx_ts; 
     1981        si->rtp_seq = call_med->rtp_tx_seq; 
     1982        si->rtp_seq_ts_set = call_med->rtp_tx_seq_ts_set; 
    17061983 
    17071984#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 
     
    17111988 
    17121989        /* Create session based on session info. */ 
    1713         status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, 
    1714                                          &call->med_tp, 
    1715                                          call, &call->session ); 
     1990        status = pjmedia_stream_create(pjsua_var.med_endpt, NULL, si, 
     1991                                       call_med->tp, NULL, 
     1992                                       &call_med->strm.a.stream); 
     1993        if (status != PJ_SUCCESS) { 
     1994            return status; 
     1995        } 
     1996 
     1997        /* Start stream */ 
     1998        status = pjmedia_stream_start(call_med->strm.a.stream); 
    17161999        if (status != PJ_SUCCESS) { 
    17172000            return status; 
     
    17222005         */ 
    17232006        if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
    1724             pjmedia_session_set_dtmf_callback(call->session, 0,  
    1725                                               &dtmf_callback,  
    1726                                               (void*)(long)(call->index)); 
     2007            pjmedia_stream_set_dtmf_callback(call_med->strm.a.stream, 
     2008                                             &dtmf_callback, 
     2009                                             (void*)(long)(call->index)); 
    17272010        } 
    17282011 
     
    17302013         * We need the port interface to add to the conference bridge. 
    17312014         */ 
    1732         pjmedia_session_get_port(call->session, 0, &media_port); 
     2015        pjmedia_stream_get_port(call_med->strm.a.stream, &media_port); 
    17332016 
    17342017        /* Notify application about stream creation. 
     
    17372020         */ 
    17382021        if (pjsua_var.ua_cfg.cb.on_stream_created) { 
    1739             pjsua_var.ua_cfg.cb.on_stream_created(call_id, call->session, 
    1740                                                   0, &media_port); 
     2022            pjsua_var.ua_cfg.cb.on_stream_created(call->index, 
     2023                                                  call_med->strm.a.stream, 
     2024                                                  strm_idx, &media_port); 
    17412025        } 
    17422026 
     
    17592043                                            media_port,  
    17602044                                            &port_name, 
    1761                                             (unsigned*)&call->conf_slot); 
     2045                                            (unsigned*) 
     2046                                            &call_med->strm.a.conf_slot); 
    17622047            if (status != PJ_SUCCESS) { 
    17632048                return status; 
     
    17662051 
    17672052        /* Call media direction */ 
    1768         call->media_dir = si->dir; 
     2053        call_med->dir = si->dir; 
    17692054 
    17702055        /* Call media state */ 
    17712056        if (call->local_hold) 
    1772             call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
    1773         else if (call->media_dir == PJMEDIA_DIR_DECODING) 
    1774             call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
     2057            call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
     2058        else if (call_med->dir == PJMEDIA_DIR_DECODING) 
     2059            call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
    17752060        else 
    1776             call->media_st = PJSUA_CALL_MEDIA_ACTIVE; 
     2061            call_med->state = PJSUA_CALL_MEDIA_ACTIVE; 
    17772062    } 
    17782063 
     
    17812066        char info[80]; 
    17822067        int info_len = 0; 
    1783         unsigned i; 
    1784  
    1785         for (i=0; i<sess_info.stream_cnt; ++i) { 
    1786             int len; 
    1787             const char *dir; 
    1788             pjmedia_stream_info *strm_info = &sess_info.stream_info[i]; 
    1789  
    1790             switch (strm_info->dir) { 
    1791             case PJMEDIA_DIR_NONE: 
    1792                 dir = "inactive"; 
    1793                 break; 
    1794             case PJMEDIA_DIR_ENCODING: 
    1795                 dir = "sendonly"; 
    1796                 break; 
    1797             case PJMEDIA_DIR_DECODING: 
    1798                 dir = "recvonly"; 
    1799                 break; 
    1800             case PJMEDIA_DIR_ENCODING_DECODING: 
    1801                 dir = "sendrecv"; 
    1802                 break; 
    1803             default: 
    1804                 dir = "unknown"; 
    1805                 break; 
     2068        int len; 
     2069        const char *dir; 
     2070 
     2071        switch (si->dir) { 
     2072        case PJMEDIA_DIR_NONE: 
     2073            dir = "inactive"; 
     2074            break; 
     2075        case PJMEDIA_DIR_ENCODING: 
     2076            dir = "sendonly"; 
     2077            break; 
     2078        case PJMEDIA_DIR_DECODING: 
     2079            dir = "recvonly"; 
     2080            break; 
     2081        case PJMEDIA_DIR_ENCODING_DECODING: 
     2082            dir = "sendrecv"; 
     2083            break; 
     2084        default: 
     2085            dir = "unknown"; 
     2086            break; 
     2087        } 
     2088        len = pj_ansi_sprintf( info+info_len, 
     2089                               ", stream #%d: %.*s (%s)", strm_idx, 
     2090                               (int)si->fmt.encoding_name.slen, 
     2091                               si->fmt.encoding_name.ptr, 
     2092                               dir); 
     2093        if (len > 0) 
     2094            info_len += len; 
     2095        PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 
     2096    } 
     2097 
     2098    return PJ_SUCCESS; 
     2099} 
     2100 
     2101pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 
     2102                                       const pjmedia_sdp_session *local_sdp, 
     2103                                       const pjmedia_sdp_session *remote_sdp) 
     2104{ 
     2105    pjsua_call *call = &pjsua_var.calls[call_id]; 
     2106    pj_pool_t *tmp_pool = call->inv->pool_prov; 
     2107    unsigned mi; 
     2108    pj_status_t status; 
     2109 
     2110    if (pjsua_get_state() != PJSUA_STATE_RUNNING) 
     2111        return PJ_EBUSY; 
     2112 
     2113    /* Destroy existing media session, if any. */ 
     2114    stop_media_session(call->index); 
     2115 
     2116    /* Reset audio_idx first */ 
     2117    call->audio_idx = -1; 
     2118 
     2119    /* Process each media stream */ 
     2120    for (mi=0; mi < call->med_cnt; ++mi) { 
     2121        pjsua_call_media *call_med = &call->media[mi]; 
     2122 
     2123        if (mi > local_sdp->media_count || 
     2124            mi > remote_sdp->media_count) 
     2125        { 
     2126            /* Something is wrong */ 
     2127            PJ_LOG(1,(THIS_FILE, "Error updating media for call %d: " 
     2128                      "invalid media index %d in SDP", call_id, mi)); 
     2129            return PJMEDIA_SDP_EINSDP; 
     2130        } 
     2131 
     2132        switch (call_med->type) { 
     2133        case PJMEDIA_TYPE_AUDIO: 
     2134            status = audio_channel_update(call_med, tmp_pool, 
     2135                                          local_sdp, remote_sdp); 
     2136            if (call->audio_idx==-1 && status==PJ_SUCCESS && 
     2137                    call_med->strm.a.stream) 
     2138            { 
     2139                call->audio_idx = mi; 
    18062140            } 
    1807             len = pj_ansi_sprintf( info+info_len, 
    1808                                    ", stream #%d: %.*s (%s)", i, 
    1809                                    (int)strm_info->fmt.encoding_name.slen, 
    1810                                    strm_info->fmt.encoding_name.ptr, 
    1811                                    dir); 
    1812             if (len > 0) 
    1813                 info_len += len; 
    1814         } 
    1815         PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 
     2141            break; 
     2142        case PJMEDIA_TYPE_VIDEO: 
     2143            PJ_LOG(4,(THIS_FILE, "-x-x-x-x-  Updating video for stream %d", mi)); 
     2144            break; 
     2145        default: 
     2146            break; 
     2147        } 
     2148 
     2149        if (status != PJ_SUCCESS) { 
     2150            PJ_PERROR(1,(THIS_FILE, status, "Error updating media call%02:%d", 
     2151                         call_id, mi)); 
     2152        } 
    18162153    } 
    18172154 
Note: See TracChangeset for help on using the changeset viewer.