diff options
author | Nanang Izzuddin <nanang@teluu.com> | 2011-12-01 09:06:14 +0000 |
---|---|---|
committer | Nanang Izzuddin <nanang@teluu.com> | 2011-12-01 09:06:14 +0000 |
commit | fb7ffe37b9ca728f0d3f6bf57b937e114d2f9161 (patch) | |
tree | bf3d2bd71b21ee29d72fd4bb99af186d8b18f064 | |
parent | 9ad8beaa148c78e04a2aac3c5ad6d85567d31b01 (diff) |
Re #1419, implement media count manipulation per call basis:
- moved the media count setting from account setting to call setting
- introduced pjsua_call_setting, to be used by pjsua_call_make_call() and some new APIs: pjsua_call_answer2(), pjsua_call_reinvite2(), pjsua_call_update2()
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3891 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r-- | pjsip-apps/src/pjsua/pjsua_app.c | 122 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua.h | 147 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua_internal.h | 8 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_acc.c | 19 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_call.c | 216 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_core.c | 1 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_media.c | 211 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_vid.c | 12 |
8 files changed, 562 insertions, 174 deletions
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index c8675ab9..7d586cec 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -134,6 +134,7 @@ static struct app_config pjmedia_port *ring_port; struct app_vid vid; + unsigned aud_cnt; } app_config; @@ -402,6 +403,7 @@ static void default_config(struct app_config *cfg) cfg->vid.vcapture_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV; cfg->vid.vrender_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV; + cfg->aud_cnt = 1; } @@ -1455,12 +1457,12 @@ static pj_status_t parse_args(int argc, char *argv[], cfg->udp_cfg.qos_params.dscp_val = 0x18; break; case OPT_VIDEO: - app_config.vid.vid_cnt = 1; - app_config.vid.in_auto_show = PJ_TRUE; - app_config.vid.out_auto_transmit = PJ_TRUE; + cfg->vid.vid_cnt = 1; + cfg->vid.in_auto_show = PJ_TRUE; + cfg->vid.out_auto_transmit = PJ_TRUE; break; case OPT_EXTRA_AUDIO: - ++cur_acc->max_audio_cnt; + cfg->aud_cnt++; break; case OPT_VCAPTURE_DEV: @@ -1717,14 +1719,6 @@ static void write_account_settings(int acc_index, pj_str_t *result) /* MWI */ if (acc_cfg->mwi_enabled) pj_strcat2(result, "--mwi\n"); - - /* Video & extra audio */ - for (i=0; i<acc_cfg->max_video_cnt; ++i) { - pj_strcat2(result, "--video\n"); - } - for (i=1; i<acc_cfg->max_audio_cnt; ++i) { - pj_strcat2(result, "--extra-audio\n"); - } } @@ -1890,6 +1884,14 @@ static int write_settings(const struct app_config *config, pj_strcat2(&cfg, "\n#\n# Media settings:\n#\n"); + /* Video & extra audio */ + for (i=0; i<config->vid.vid_cnt; ++i) { + pj_strcat2(&cfg, "--video\n"); + } + for (i=1; i<config->aud_cnt; ++i) { + pj_strcat2(&cfg, "--extra-audio\n"); + } + /* SRTP */ #if PJMEDIA_HAS_SRTP if (app_config.cfg.use_srtp != PJSUA_DEFAULT_USE_SRTP) { @@ -2575,16 +2577,39 @@ static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, ring_start(call_id); if (app_config.auto_answer > 0) { - pjsua_call_answer(call_id, app_config.auto_answer, NULL, NULL); - } + pjsua_call_setting call_opt; + + pjsua_call_setting_default(&call_opt); + call_opt.audio_cnt = app_config.aud_cnt; + call_opt.video_cnt = app_config.vid.vid_cnt; + pjsua_call_answer2(call_id, &call_opt, app_config.auto_answer, NULL, NULL); + } + if (app_config.auto_answer < 200) { + char notif_st[80] = {0}; + +#if PJSUA_HAS_VIDEO + if (call_info.rem_offerer && call_info.rem_video_cnt) { + snprintf(notif_st, sizeof(notif_st), + "To %s the video, type \"vid %s\" first, " + "before answering the call!\n", + (app_config.vid.vid_cnt? "reject":"accept"), + (app_config.vid.vid_cnt? "disable":"enable")); + } +#endif + PJ_LOG(3,(THIS_FILE, "Incoming call for account %d!\n" + "Media count: %d audio & %d video\n" + "%s" "From: %s\n" "To: %s\n" "Press a to answer or h to reject call", acc_id, + call_info.rem_audio_cnt, + call_info.rem_video_cnt, + notif_st, call_info.remote_info.ptr, call_info.local_info.ptr)); } @@ -2846,6 +2871,23 @@ static void on_call_media_state(pjsua_call_id call_id) pj_str_t reason = pj_str("Media failed"); pjsua_call_hangup(call_id, 500, &reason, NULL); } + +#if PJSUA_HAS_VIDEO + /* Check if remote has just tried to enable video */ + if (call_info.rem_offerer && call_info.rem_video_cnt) + { + int vid_idx; + + /* Check if there is active video */ + vid_idx = pjsua_call_get_vid_stream_idx(call_id); + if (vid_idx == -1 || call_info.media[vid_idx].dir == PJMEDIA_DIR_NONE) { + PJ_LOG(3,(THIS_FILE, + "Just rejected incoming video offer on call %d" + "use \"vid call add\" to enable video!", + call_id)); + } + } +#endif } /* @@ -3422,12 +3464,14 @@ static void keystroke_help(void) static void vid_show_help(void) { #if PJSUA_HAS_VIDEO + pj_bool_t vid_enabled = (app_config.vid.vid_cnt > 0); + puts("+=============================================================================+"); puts("| Video commands: |"); puts("| |"); puts("| vid help Show this help screen |"); + puts("| vid enable|disable Enable or disable video in next offer/answer |"); puts("| vid acc show Show current account video settings |"); - puts("| vid acc enable|disable Enable or disable video on current account |"); puts("| vid acc autorx on|off Automatically show incoming video on/off |"); puts("| vid acc autotx on|off Automatically offer video on/off |"); puts("| vid acc cap ID Set default capture device for current acc |"); @@ -3435,7 +3479,7 @@ static void vid_show_help(void) puts("| vid call rx on|off N Enable/disable video rx for stream N in curr call |"); puts("| vid call tx on|off N Enable/disable video tx for stream N in curr call |"); puts("| vid call add Add video stream for current call |"); - puts("| vid call enable/disable N Enable/disable stream #N in current call |"); + puts("| vid call enable|disable N Enable/disable stream #N in current call |"); puts("| vid call cap N ID Set capture dev ID for stream #N in current call |"); puts("| vid dev list List all video devices |"); puts("| vid dev refresh Refresh video device list |"); @@ -3448,6 +3492,9 @@ static void vid_show_help(void) puts("| vid win move ID X Y Move window ID to position X,Y |"); puts("| vid win resize ID w h Resize window ID to the specified width, height |"); puts("+=============================================================================+"); + printf("| Video will be %s in the next offer/answer %s |\n", + (vid_enabled? "enabled" : "disabled"), (vid_enabled? " " : "")); + puts("+=============================================================================+"); #endif } @@ -3863,7 +3910,6 @@ static void vid_list_devs(void) static void app_config_init_video(pjsua_acc_config *acc_cfg) { - acc_cfg->max_video_cnt = app_config.vid.vid_cnt; acc_cfg->vid_in_auto_show = app_config.vid.in_auto_show; acc_cfg->vid_out_auto_transmit = app_config.vid.out_auto_transmit; /* Note that normally GUI application will prefer a borderless @@ -3879,13 +3925,11 @@ static void app_config_show_video(int acc_id, const pjsua_acc_config *acc_cfg) { PJ_LOG(3,(THIS_FILE, "Account %d:\n" - " Video count: %d\n" " RX auto show: %d\n" " TX auto transmit: %d\n" " Capture dev: %d\n" " Render dev: %d", acc_id, - acc_cfg->max_video_cnt, acc_cfg->vid_in_auto_show, acc_cfg->vid_out_auto_transmit, acc_cfg->vid_cap_dev, @@ -3906,6 +3950,13 @@ static void vid_handle_menu(char *menuin) if (argc == 1 || strcmp(argv[1], "help")==0) { vid_show_help(); + } else if (argc == 2 && (strcmp(argv[1], "enable")==0 || + strcmp(argv[1], "disable")==0)) + { + pj_bool_t enabled = (strcmp(argv[1], "enable")==0); + app_config.vid.vid_cnt = (enabled ? 1 : 0); + PJ_LOG(3,(THIS_FILE, "Video will be %s in next offer/answer", + (enabled?"enabled":"disabled"))); } else if (strcmp(argv[1], "acc")==0) { pjsua_acc_config acc_cfg; pj_bool_t changed = PJ_FALSE; @@ -3914,17 +3965,6 @@ static void vid_handle_menu(char *menuin) if (argc == 3 && strcmp(argv[2], "show")==0) { app_config_show_video(current_acc, &acc_cfg); - - } else if (argc == 3 && (strcmp(argv[2], "enable")==0 || - strcmp(argv[2], "disable")==0)) - { - int enabled = (strcmp(argv[2], "enable")==0); - acc_cfg.max_video_cnt = (enabled ? 1 : 0); - if (enabled) { - app_config_init_video(&acc_cfg); - acc_cfg.max_video_cnt = (enabled ? 1 : 0); - } - changed = PJ_TRUE; } else if (argc == 4 && strcmp(argv[2], "autorx")==0) { int on = (strcmp(argv[3], "on")==0); acc_cfg.vid_in_auto_show = on; @@ -4165,11 +4205,15 @@ void console_app_main(const pj_str_t *uri_to_call) pjsua_msg_data msg_data; pjsua_call_info call_info; pjsua_acc_info acc_info; + pjsua_call_setting call_opt; + pjsua_call_setting_default(&call_opt); + call_opt.audio_cnt = app_config.aud_cnt; + call_opt.video_cnt = app_config.vid.vid_cnt; /* If user specifies URI to call, then call the URI */ if (uri_to_call->slen) { - pjsua_call_make_call( current_acc, uri_to_call, 0, NULL, NULL, NULL); + pjsua_call_make_call( current_acc, uri_to_call, &call_opt, NULL, NULL, NULL); } keystroke_help(); @@ -4204,6 +4248,11 @@ void console_app_main(const pj_str_t *uri_to_call) printf("%s", menuin); } + /* Update call setting */ + pjsua_call_setting_default(&call_opt); + call_opt.audio_cnt = app_config.aud_cnt; + call_opt.video_cnt = app_config.vid.vid_cnt; + switch (menuin[0]) { case 'm': @@ -4233,7 +4282,7 @@ void console_app_main(const pj_str_t *uri_to_call) pjsua_msg_data_init(&msg_data); TEST_MULTIPART(&msg_data); - pjsua_call_make_call( current_acc, &tmp, 0, NULL, &msg_data, NULL); + pjsua_call_make_call( current_acc, &tmp, &call_opt, NULL, &msg_data, NULL); break; case 'M': @@ -4265,7 +4314,7 @@ void console_app_main(const pj_str_t *uri_to_call) for (i=0; i<my_atoi(menuin); ++i) { pj_status_t status; - status = pjsua_call_make_call(current_acc, &tmp, 0, NULL, + status = pjsua_call_make_call(current_acc, &tmp, &call_opt, NULL, NULL, NULL); if (status != PJ_SUCCESS) break; @@ -4402,7 +4451,7 @@ void console_app_main(const pj_str_t *uri_to_call) continue; } - pjsua_call_answer(current_call, st_code, NULL, &msg_data); + pjsua_call_answer2(current_call, &call_opt, st_code, NULL, &msg_data); } break; @@ -4591,7 +4640,8 @@ void console_app_main(const pj_str_t *uri_to_call) /* * re-INVITE */ - pjsua_call_reinvite(current_call, PJ_TRUE, NULL); + call_opt.flag |= PJSUA_CALL_UNHOLD; + pjsua_call_reinvite2(current_call, &call_opt, NULL); } else { PJ_LOG(3,(THIS_FILE, "No current call")); @@ -4604,7 +4654,7 @@ void console_app_main(const pj_str_t *uri_to_call) */ if (current_call != -1) { - pjsua_call_update(current_call, 0, NULL); + pjsua_call_update2(current_call, &call_opt, NULL); } else { PJ_LOG(3,(THIS_FILE, "No current call")); diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index b45f69f7..31fbfca1 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -2697,24 +2697,6 @@ typedef struct pjsua_acc_config pj_str_t ka_data; /** - * Maximum number of simultaneous active audio streams to be allowed - * for calls on this account. Setting this to zero will disable audio - * in calls on this account. - * - * Default: 1 - */ - unsigned max_audio_cnt; - - /** - * Maximum number of simultaneous active video streams to be allowed - * for calls on this account. Setting this to zero will disable video - * in calls on this account, regardless of other video settings. - * - * Default: 1 - */ - unsigned max_video_cnt; - - /** * Specify whether incoming video should be shown to screen by default. * This applies to incoming call (INVITE), incoming re-INVITE, and * incoming UPDATE requests. @@ -3389,6 +3371,37 @@ typedef enum pjsua_call_media_status /** + * Call settings. + */ +typedef struct pjsua_call_setting +{ + /** + * Bitmask of pjsua_call_flag constants. + * + * Default: 0 + */ + unsigned flag; + + /** + * Number of simultaneous active audio streams for this call. Setting + * this to zero will disable audio in this call. + * + * Default: 1 + */ + unsigned audio_cnt; + + /** + * Number of simultaneous active video streams for this call. Setting + * this to zero will disable video in this call. + * + * Default: 1 (if video feature is enabled, otherwise it is zero) + */ + unsigned video_cnt; + +} pjsua_call_setting; + + +/** * This structure describes the information and current status of a call. */ typedef struct pjsua_call_info @@ -3417,6 +3430,9 @@ typedef struct pjsua_call_info /** Dialog Call-ID string. */ pj_str_t call_id; + /** Call setting */ + pjsua_call_setting setting; + /** Call state */ pjsip_inv_state state; @@ -3490,6 +3506,15 @@ typedef struct pjsua_call_info /** Total call duration, including set-up time */ pj_time_val total_duration; + /** Flag if remote was SDP offerer */ + pj_bool_t rem_offerer; + + /** Number of audio streams offered by remote */ + unsigned rem_audio_cnt; + + /** Number of video streams offered by remote */ + unsigned rem_video_cnt; + /** Internal */ struct { char local_info[128]; @@ -3525,7 +3550,14 @@ typedef enum pjsua_call_flag * session with the new Contact and to inform this new Contact to the * remote peer with the outgoing re-INVITE or UPDATE */ - PJSUA_CALL_UPDATE_CONTACT = 2 + PJSUA_CALL_UPDATE_CONTACT = 2, + + /** + * Include SDP "m=" line with port set to zero for each disabled media + * (i.e when aud_cnt or vid_cnt is set to zero). This flag is only valid + * for #pjsua_call_make_call(). + */ + PJSUA_CALL_INCLUDE_DISABLED_MEDIA = 4 } pjsua_call_flag; @@ -3578,8 +3610,7 @@ typedef enum pjsua_call_vid_strm_op * Add a new video stream. This will add a new m=video line to * the media, regardless of whether existing video is/are present * or not. This will cause re-INVITE or UPDATE to be sent to remote - * party. The number of maximum active video streams in a call is - * still limited by \a max_video_cnt setting in pjsua_acc_config. + * party. */ PJSUA_CALL_VID_STRM_ADD, @@ -3667,6 +3698,14 @@ typedef struct pjsua_call_vid_strm_op_param /** + * Initialize call settings. + * + * @param opt The call setting to be initialized. + */ +PJ_DECL(void) pjsua_call_setting_default(pjsua_call_setting *opt); + + +/** * Initialize video stream operation param with default values. * * @param param The video stream operation param to be initialized. @@ -3709,7 +3748,8 @@ PJ_DECL(pj_status_t) pjsua_enum_calls(pjsua_call_id ids[], * @param acc_id The account to be used. * @param dst_uri URI to be put in the To header (normally is the same * as the target URI). - * @param options Options (must be zero at the moment). + * @param opt Optional call setting. This should be initialized + * using #pjsua_call_setting_default(). * @param user_data Arbitrary user data to be attached to the call, and * can be retrieved later. * @param msg_data Optional headers etc to be added to outgoing INVITE @@ -3720,7 +3760,7 @@ PJ_DECL(pj_status_t) pjsua_enum_calls(pjsua_call_id ids[], */ PJ_DECL(pj_status_t) pjsua_call_make_call(pjsua_acc_id acc_id, const pj_str_t *dst_uri, - unsigned options, + const pjsua_call_setting *opt, void *user_data, const pjsua_msg_data *msg_data, pjsua_call_id *p_call_id); @@ -3862,6 +3902,29 @@ PJ_DECL(pj_status_t) pjsua_call_answer(pjsua_call_id call_id, const pj_str_t *reason, const pjsua_msg_data *msg_data); + +/** + * Send response to incoming INVITE request. Depending on the status + * code specified as parameter, this function may send provisional + * response, establish the call, or terminate the call. + * + * @param call_id Incoming call identification. + * @param opt Optional call setting. + * @param code Status code, (100-699). + * @param reason Optional reason phrase. If NULL, default text + * will be used. + * @param msg_data Optional list of headers etc to be added to outgoing + * response message. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsua_call_answer2(pjsua_call_id call_id, + const pjsua_call_setting *opt, + unsigned code, + const pj_str_t *reason, + const pjsua_msg_data *msg_data); + + /** * Hangup call by using method that is appropriate according to the * call state. This function is different than answering the call with @@ -3949,6 +4012,25 @@ PJ_DECL(pj_status_t) pjsua_call_reinvite(pjsua_call_id call_id, unsigned options, const pjsua_msg_data *msg_data); + +/** + * Send re-INVITE to release hold. + * The final status of the request itself will be reported on the + * \a on_call_media_state() callback, which inform the application that + * the media state of the call has changed. + * + * @param call_id Call identification. + * @param opt Optional call setting. + * @param msg_data Optional message components to be sent with + * the request. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsua_call_reinvite2(pjsua_call_id call_id, + const pjsua_call_setting *opt, + const pjsua_msg_data *msg_data); + + /** * Send UPDATE request. * @@ -3963,6 +4045,22 @@ PJ_DECL(pj_status_t) pjsua_call_update(pjsua_call_id call_id, unsigned options, const pjsua_msg_data *msg_data); + +/** + * Send UPDATE request. + * + * @param call_id Call identification. + * @param opt Optional call setting. + * @param msg_data Optional message components to be sent with + * the request. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsua_call_update2(pjsua_call_id call_id, + const pjsua_call_setting *opt, + const pjsua_msg_data *msg_data); + + /** * Initiate call transfer to the specified address. This function will send * REFER request to instruct remote call party to initiate a new INVITE @@ -4106,7 +4204,8 @@ PJ_DECL(pj_status_t) pjsua_call_dump(pjsua_call_id call_id, /** * Get the media stream index of the default video stream in the call. * Typically this will just retrieve the stream index of the first - * activated video stream in the call. + * activated video stream in the call. If none is active, it will return + * the first inactive video stream. * * @param call_id Call identification. * diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index db566ed5..31d303f0 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -120,6 +120,7 @@ typedef struct call_answer struct pjsua_call { unsigned index; /**< Index in pjsua array. */ + pjsua_call_setting opt; /**< Call setting. */ pjsip_inv_session *inv; /**< The invite session. */ void *user_data; /**< User/application data. */ pjsip_status_code last_code; /**< Last status code seen. */ @@ -162,7 +163,6 @@ struct pjsua_call pj_bool_t med_ch_deinit;/**< Media channel de-init-ed? */ union { struct { - unsigned options; /**< Outgoing call options. */ pjsua_msg_data *msg_data;/**< Headers for outgoing INVITE. */ } out_call; struct { @@ -171,6 +171,12 @@ struct pjsua_call } call_var; } async_call; /**< Temporary storage for async outgoing/incoming call. */ + + pj_bool_t rem_offerer; /**< Was remote SDP offerer? */ + unsigned rem_aud_cnt; /**< No of active audio in last remote + offer. */ + unsigned rem_vid_cnt; /**< No of active video in last remote + offer. */ }; diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 24df6e01..b8f0dd8e 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -383,14 +383,6 @@ PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg, /* Must have a transport */ PJ_ASSERT_RETURN(pjsua_var.tpdata[0].data.ptr != NULL, PJ_EINVALIDOP); - /* Verify media count */ -#if !defined(PJMEDIA_HAS_VIDEO) || (PJMEDIA_HAS_VIDEO == 0) - /* Enable PJMEDIA_HAS_VIDEO in your config_site.h! */ - PJ_ASSERT_RETURN(cfg->max_video_cnt == 0, PJ_EINVAL); -#endif - PJ_ASSERT_RETURN(cfg->max_audio_cnt + cfg->max_video_cnt <= - PJSUA_MAX_CALL_MEDIA, PJ_ETOOMANY); - PJ_LOG(4,(THIS_FILE, "Adding account: id=%.*s", (int)cfg->id.slen, cfg->id.ptr)); pj_log_push_indent(); @@ -674,13 +666,6 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id, PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc), PJ_EINVAL); - /* Verify media count */ -#if !defined(PJMEDIA_HAS_VIDEO) || (PJMEDIA_HAS_VIDEO == 0) - PJ_ASSERT_RETURN(cfg->max_video_cnt == 0, PJ_EINVAL); -#endif - PJ_ASSERT_RETURN(cfg->max_audio_cnt + cfg->max_video_cnt <= - PJSUA_MAX_CALL_MEDIA, PJ_ETOOMANY); - PJ_LOG(4,(THIS_FILE, "Modifying accunt %d", acc_id)); pj_log_push_indent(); @@ -1064,10 +1049,6 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id, } } - /* Max number of audio and video stream in a call */ - acc->cfg.max_audio_cnt = cfg->max_audio_cnt; - acc->cfg.max_video_cnt = cfg->max_video_cnt; - /* Video settings */ acc->cfg.vid_in_auto_show = cfg->vid_in_auto_show; acc->cfg.vid_out_auto_transmit = cfg->vid_out_auto_transmit; diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index 1e337dd6..cec75935 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -116,6 +116,7 @@ static void reset_call(pjsua_call_id id) call_med->idx = i; call_med->tp_auto_del = PJ_TRUE; } + pjsua_call_setting_default(&call->opt); } @@ -341,7 +342,7 @@ on_make_call_med_tp_complete(pjsua_call_id call_id, pjsua_call *call = &pjsua_var.calls[call_id]; pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; pjsip_dialog *dlg = call->async_call.dlg; - unsigned options = call->async_call.call_var.out_call.options; + unsigned options = 0; pjsip_tx_data *tdata; pj_status_t status = (info? info->status: PJ_SUCCESS); @@ -487,14 +488,79 @@ on_error: /* + * Initialize call settings based on account ID. + */ +PJ_DEF(void) pjsua_call_setting_default(pjsua_call_setting *opt) +{ + pj_assert(opt); + + pj_bzero(opt, sizeof(*opt)); + opt->flag = PJSUA_CALL_INCLUDE_DISABLED_MEDIA; + opt->audio_cnt = 1; + +#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) + opt->video_cnt = 1; + //{ + // unsigned i; + // for (i = 0; i < PJ_ARRAY_SIZE(opt->vid_cap_dev); ++i) + // opt->vid_cap_dev[i] = PJMEDIA_VID_DEFAULT_CAPTURE_DEV; + //} +#endif +} + +static pj_status_t apply_call_setting(pjsua_call *call, + const pjsua_call_setting *opt, + const pjmedia_sdp_session *rem_sdp) +{ + pj_assert(call); + + if (!opt) + return PJ_SUCCESS; + +#if !PJMEDIA_HAS_VIDEO + pj_assert(opt->video_cnt == 0); +#endif + + /* If call is established, reinit media channel */ + if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) { + pjsua_call_setting old_opt; + pj_status_t status; + + old_opt = call->opt; + call->opt = *opt; + + /* Reinit media channel when media count is changed */ + if (opt->audio_cnt != old_opt.audio_cnt || + opt->video_cnt != old_opt.video_cnt) + { + pjsip_role_e role = rem_sdp? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC; + status = pjsua_media_channel_init(call->index, role, + call->secure_level, + call->inv->pool_prov, + rem_sdp, NULL, + PJ_FALSE, NULL); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Error re-initializing media channel", + status); + return status; + } + } + } else { + call->opt = *opt; + } + + return PJ_SUCCESS; +} + +/* * Make outgoing call to the specified URI using the specified account. */ -PJ_DEF(pj_status_t) pjsua_call_make_call( pjsua_acc_id acc_id, - const pj_str_t *dest_uri, - unsigned options, - void *user_data, - const pjsua_msg_data *msg_data, - pjsua_call_id *p_call_id) +PJ_DEF(pj_status_t) pjsua_call_make_call(pjsua_acc_id acc_id, + const pj_str_t *dest_uri, + const pjsua_call_setting *opt, + void *user_data, + const pjsua_msg_data *msg_data, + pjsua_call_id *p_call_id) { pj_pool_t *tmp_pool = NULL; pjsip_dialog *dlg = NULL; @@ -555,6 +621,13 @@ PJ_DEF(pj_status_t) pjsua_call_make_call( pjsua_acc_id acc_id, call->acc_id = acc_id; call->call_hold_type = acc->cfg.call_hold_type; + /* Apply call setting */ + status = apply_call_setting(call, opt, NULL); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Failed to apply call setting", status); + goto on_error; + } + /* Create temporary pool */ tmp_pool = pjsua_pool_create("tmpcall10", 512, 256); @@ -622,7 +695,6 @@ PJ_DEF(pj_status_t) pjsua_call_make_call( pjsua_acc_id acc_id, /* Store variables required for the callback after the async * media transport creation is completed. */ - call->async_call.call_var.out_call.options = options; if (msg_data) { call->async_call.call_var.out_call.msg_data = pjsua_msg_data_clone( dlg->pool, msg_data); @@ -1465,6 +1537,9 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id, pj_strncpy(&info->call_id, &dlg->call_id->id, sizeof(info->buf_.call_id)); + /* call setting */ + pj_memcpy(&info->setting, &call->opt, sizeof(call->opt)); + /* state, state_text */ info->state = (call->inv? call->inv->state: PJSIP_INV_STATE_DISCONNECTED); info->state_text = pj_str((char*)pjsip_inv_state_name(info->state)); @@ -1486,6 +1561,13 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id, sizeof(info->buf_.last_status_text)); } + /* Audio & video count offered by remote */ + info->rem_offerer = call->rem_offerer; + if (call->rem_offerer) { + info->rem_audio_cnt = call->rem_aud_cnt; + info->rem_video_cnt = call->rem_vid_cnt; + } + /* Build array of media status and dir */ info->media_cnt = 0; for (mi=0; mi < call->med_cnt && @@ -1760,6 +1842,19 @@ PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id, const pj_str_t *reason, const pjsua_msg_data *msg_data) { + return pjsua_call_answer2(call_id, NULL, code, reason, msg_data); +} + + +/* + * Send response to incoming INVITE request. + */ +PJ_DEF(pj_status_t) pjsua_call_answer2(pjsua_call_id call_id, + const pjsua_call_setting *opt, + unsigned code, + const pj_str_t *reason, + const pjsua_msg_data *msg_data) +{ pjsua_call *call; pjsip_dialog *dlg = NULL; pjsip_tx_data *tdata; @@ -1775,6 +1870,13 @@ PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id, if (status != PJ_SUCCESS) goto on_return; + /* Apply call setting */ + status = apply_call_setting(call, opt, NULL); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Failed to apply call setting", status); + goto on_return; + } + PJSUA_LOCK(); /* If media transport creation is not yet completed, we will answer * the call in the media transport creation callback instead. @@ -2016,6 +2118,32 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, unsigned options, const pjsua_msg_data *msg_data) { + pjsua_call *call; + pjsip_dialog *dlg = NULL; + pj_status_t status; + + status = acquire_call("pjsua_call_reinvite()", call_id, &call, &dlg); + if (status != PJ_SUCCESS) + goto on_return; + + if (options != call->opt.flag) + call->opt.flag = options; + + status = pjsua_call_reinvite2(call_id, NULL, msg_data); + +on_return: + if (dlg) pjsip_dlg_dec_lock(dlg); + return status; +} + + +/* + * Send re-INVITE (to release hold). + */ +PJ_DEF(pj_status_t) pjsua_call_reinvite2(pjsua_call_id call_id, + const pjsua_call_setting *opt, + const pjsua_msg_data *msg_data) +{ pjmedia_sdp_session *sdp; pj_str_t *new_contact = NULL; pjsip_tx_data *tdata; @@ -2030,7 +2158,7 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, PJ_LOG(4,(THIS_FILE, "Sending re-INVITE on call %d", call_id)); pj_log_push_indent(); - status = acquire_call("pjsua_call_reinvite()", call_id, &call, &dlg); + status = acquire_call("pjsua_call_reinvite2()", call_id, &call, &dlg); if (status != PJ_SUCCESS) goto on_return; @@ -2040,8 +2168,14 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, goto on_return; } + status = apply_call_setting(call, opt, NULL); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Failed to apply call setting", status); + goto on_return; + } + /* Create SDP */ - if (call->local_hold && (options & PJSUA_CALL_UNHOLD)==0) { + if (call->local_hold && (call->opt.flag & PJSUA_CALL_UNHOLD)==0) { status = create_sdp_of_call_hold(call, &sdp); } else { status = pjsua_media_channel_create_sdp(call->index, @@ -2055,7 +2189,7 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, goto on_return; } - if ((options & PJSUA_CALL_UPDATE_CONTACT) & + if ((call->opt.flag & PJSUA_CALL_UPDATE_CONTACT) & pjsua_acc_is_valid(call->acc_id)) { new_contact = &pjsua_var.acc[call->acc_id].contact; @@ -2092,6 +2226,32 @@ PJ_DEF(pj_status_t) pjsua_call_update( pjsua_call_id call_id, unsigned options, const pjsua_msg_data *msg_data) { + pjsua_call *call; + pjsip_dialog *dlg = NULL; + pj_status_t status; + + status = acquire_call("pjsua_call_update()", call_id, &call, &dlg); + if (status != PJ_SUCCESS) + goto on_return; + + if (options != call->opt.flag) + call->opt.flag = options; + + status = pjsua_call_update2(call_id, NULL, msg_data); + +on_return: + if (dlg) pjsip_dlg_dec_lock(dlg); + return status; +} + + +/* + * Send UPDATE request. + */ +PJ_DEF(pj_status_t) pjsua_call_update2(pjsua_call_id call_id, + const pjsua_call_setting *opt, + const pjsua_msg_data *msg_data) +{ pjmedia_sdp_session *sdp; pj_str_t *new_contact = NULL; pjsip_tx_data *tdata; @@ -2099,18 +2259,22 @@ PJ_DEF(pj_status_t) pjsua_call_update( pjsua_call_id call_id, pjsip_dialog *dlg = NULL; pj_status_t status; - PJ_UNUSED_ARG(options); - PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); PJ_LOG(4,(THIS_FILE, "Sending UPDATE on call %d", call_id)); pj_log_push_indent(); - status = acquire_call("pjsua_call_update()", call_id, &call, &dlg); + status = acquire_call("pjsua_call_update2()", call_id, &call, &dlg); if (status != PJ_SUCCESS) goto on_return; + status = apply_call_setting(call, opt, NULL); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Failed to apply call setting", status); + goto on_return; + } + /* Create SDP */ status = pjsua_media_channel_create_sdp(call->index, call->inv->pool_prov, @@ -2121,7 +2285,7 @@ PJ_DEF(pj_status_t) pjsua_call_update( pjsua_call_id call_id, goto on_return; } - if ((options & PJSUA_CALL_UPDATE_CONTACT) & + if ((call->opt.flag & PJSUA_CALL_UPDATE_CONTACT) & pjsua_acc_is_valid(call->acc_id)) { new_contact = &pjsua_var.acc[call->acc_id].contact; @@ -3356,6 +3520,7 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv, pjsua_call *call; pjmedia_sdp_session *answer; unsigned i; + int vid_idx; pj_status_t status; PJSUA_LOCK(); @@ -3367,6 +3532,27 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv, call->index)); pj_log_push_indent(); +#if 0 && PJMEDIA_HAS_VIDEO + /* If current session has no video, let's just stay with no video. + * If application want to enable video, it must send re-INVITE + * with video. + */ + vid_idx = pjsua_call_get_vid_stream_idx(call->index); + if (vid_idx == -1 || call->media[vid_idx].dir == PJMEDIA_DIR_NONE) + call->opt.video_cnt = 0; +#endif + + /* Re-init media for the new remote offer before creating SDP */ + status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS, + call->secure_level, + call->inv->pool_prov, + offer, NULL, + PJ_FALSE, NULL); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Error re-initializing media channel", status); + goto on_return; + } + status = pjsua_media_channel_create_sdp(call->index, call->inv->pool_prov, offer, &answer, NULL); diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 6a80380c..fc47121d 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -216,7 +216,6 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg) cfg->timer_setting = pjsua_var.ua_cfg.timer_setting; cfg->ka_interval = 15; cfg->ka_data = pj_str("\r\n"); - cfg->max_audio_cnt = 1; cfg->vid_cap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV; cfg->vid_rend_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV; pjsua_transport_config_default(&cfg->rtp_cfg); diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 8fe57a11..138f4808 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -1157,15 +1157,18 @@ static void sort_media(const pjmedia_sdp_session *sdp, const pj_str_t *type, pjmedia_srtp_use use_srtp, pj_uint8_t midx[], - unsigned *p_count) + unsigned *p_count, + unsigned *p_total_count) { unsigned i; unsigned count = 0; int score[PJSUA_MAX_CALL_MEDIA]; pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA); + pj_assert(*p_total_count >= PJSUA_MAX_CALL_MEDIA); *p_count = 0; + *p_total_count = 0; for (i=0; i<PJSUA_MAX_CALL_MEDIA; ++i) score[i] = 1; @@ -1238,10 +1241,11 @@ static void sort_media(const pjmedia_sdp_session *sdp, /* Don't put media with negative score, that media is unacceptable * for us. */ - if (score[best] >= 0) { - midx[*p_count] = (pj_uint8_t)best; + midx[i] = (pj_uint8_t)best; + if (score[best] >= 0) (*p_count)++; - } + if (score[best] > -22000) + (*p_total_count)++; score[best] = -22000; @@ -1588,11 +1592,13 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); + unsigned mtotaudcnt = PJ_ARRAY_SIZE(maudidx); pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA]; unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx); - pjmedia_type media_types[PJSUA_MAX_CALL_MEDIA]; + unsigned mtotvidcnt = PJ_ARRAY_SIZE(mvididx); unsigned mi; pj_bool_t pending_med_tp = PJ_FALSE; + pj_bool_t reinit = PJ_FALSE; pj_status_t status; PJ_UNUSED_ARG(role); @@ -1614,7 +1620,12 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, return status; } - PJ_LOG(4,(THIS_FILE, "Call %d: initializing media..", call_id)); + if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) + reinit = PJ_TRUE; + + PJ_LOG(4,(THIS_FILE, "Call %d: %sinitializing media..", + call_id, (reinit?"re-":"") )); + pj_log_push_indent(); #if DISABLED_FOR_TICKET_1185 @@ -1629,13 +1640,10 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, } #endif + /* Get media count for each media type */ if (rem_sdp) { sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, - maudidx, &maudcnt); - // Don't apply media count limitation until SDP negotiation is done. - //if (maudcnt > acc->cfg.max_audio_cnt) - // maudcnt = acc->cfg.max_audio_cnt; - + maudidx, &maudcnt, &mtotaudcnt); if (maudcnt==0) { /* Expecting audio in the offer */ if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; @@ -1646,35 +1654,98 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, #if PJMEDIA_HAS_VIDEO sort_media(rem_sdp, &STR_VIDEO, acc->cfg.use_srtp, - mvididx, &mvidcnt); - // Don't apply media count limitation until SDP negotiation is done. - //if (mvidcnt > acc->cfg.max_video_cnt) - //mvidcnt = acc->cfg.max_video_cnt; + mvididx, &mvidcnt, &mtotvidcnt); #else - mvidcnt = 0; + mvidcnt = mtotvidcnt = 0; + PJ_UNUSED_ARG(STR_VIDEO); #endif /* Update media count only when remote add any media, this media count - * must never decrease. + * must never decrease. Also note that we shouldn't apply the media + * count setting (of the call setting) before the SDP negotiation. */ if (call->med_cnt < rem_sdp->media_count) call->med_cnt = PJ_MIN(rem_sdp->media_count, PJSUA_MAX_CALL_MEDIA); + call->rem_offerer = PJ_TRUE; + call->rem_aud_cnt = maudcnt; + call->rem_vid_cnt = mvidcnt; + } else { - maudcnt = acc->cfg.max_audio_cnt; - for (mi=0; mi<maudcnt; ++mi) { - maudidx[mi] = (pj_uint8_t)mi; - media_types[mi] = PJMEDIA_TYPE_AUDIO; - } + + /* If call already established, calculate media count from current + * local active SDP and call setting. Otherwise, calculate media + * count from the call setting only. + */ + if (reinit) { + pjmedia_sdp_session *sdp; + + status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp); + pj_assert(status == PJ_SUCCESS); + + sort_media(sdp, &STR_AUDIO, acc->cfg.use_srtp, + maudidx, &maudcnt, &mtotaudcnt); + pj_assert(maudcnt > 0); + + sort_media(sdp, &STR_VIDEO, acc->cfg.use_srtp, + mvididx, &mvidcnt, &mtotvidcnt); + + /* Call setting may add or remove media. Adding media is done by + * enabling any disabled/port-zeroed media first, then adding new + * media whenever needed. Removing media is done by disabling + * media with the lowest 'quality'. + */ + + /* Check if we need to add new audio */ + if (maudcnt < call->opt.audio_cnt && + mtotaudcnt < call->opt.audio_cnt) + { + for (mi = 0; mi < call->opt.audio_cnt - mtotaudcnt; ++mi) + maudidx[maudcnt++] = (pj_uint8_t)call->med_cnt++; + + mtotaudcnt = call->opt.audio_cnt; + } + maudcnt = call->opt.audio_cnt; + + /* Check if we need to add new video */ + if (mvidcnt < call->opt.video_cnt && + mtotvidcnt < call->opt.video_cnt) + { + for (mi = 0; mi < call->opt.video_cnt - mtotvidcnt; ++mi) + mvididx[mvidcnt++] = (pj_uint8_t)call->med_cnt++; + + mtotvidcnt = call->opt.video_cnt; + } + mvidcnt = call->opt.video_cnt; + + } else { + + maudcnt = mtotaudcnt = call->opt.audio_cnt; + for (mi=0; mi<maudcnt; ++mi) { + maudidx[mi] = (pj_uint8_t)mi; + } + mvidcnt = mtotvidcnt = call->opt.video_cnt; + for (mi=0; mi<mvidcnt; ++mi) { + mvididx[mi] = (pj_uint8_t)(maudcnt + mi); + } + call->med_cnt = maudcnt + mvidcnt; + + /* Need to publish supported media? */ + if (call->opt.flag & PJSUA_CALL_INCLUDE_DISABLED_MEDIA) { + if (mtotaudcnt == 0) { + mtotaudcnt = 1; + maudidx[0] = (pj_uint8_t)call->med_cnt++; + } #if PJMEDIA_HAS_VIDEO - mvidcnt = acc->cfg.max_video_cnt; - for (mi=0; mi<mvidcnt; ++mi) { - media_types[maudcnt + mi] = PJMEDIA_TYPE_VIDEO; + if (mtotvidcnt == 0) { + mtotvidcnt = 1; + mvididx[0] = (pj_uint8_t)call->med_cnt++; + } +#endif + } } -#else - mvidcnt = 0; -#endif - call->med_cnt = maudcnt + mvidcnt; + + call->rem_offerer = PJ_FALSE; } if (call->med_cnt == 0) { @@ -1702,28 +1773,22 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, for (mi=0; mi < call->med_cnt; ++mi) { pjsua_call_media *call_med = &call->media[mi]; pj_bool_t enabled = PJ_FALSE; - pjmedia_type media_type = PJMEDIA_TYPE_NONE; - - if (rem_sdp) { - if (mi >= rem_sdp->media_count) { - /* Media has been removed in remote re-offer */ - media_type = call_med->type; - } else if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_AUDIO)) { - media_type = PJMEDIA_TYPE_AUDIO; - if (pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0]))) { - enabled = PJ_TRUE; - } + pjmedia_type media_type = PJMEDIA_TYPE_UNKNOWN; + + if (pj_memchr(maudidx, mi, mtotaudcnt * sizeof(maudidx[0]))) { + media_type = PJMEDIA_TYPE_AUDIO; + if (call->opt.audio_cnt && + pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0]))) + { + enabled = PJ_TRUE; } - else if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_VIDEO)) { - media_type = PJMEDIA_TYPE_VIDEO; - if (pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0]))) { - enabled = PJ_TRUE; - } + } else if (pj_memchr(mvididx, mi, mtotvidcnt * sizeof(mvididx[0]))) { + media_type = PJMEDIA_TYPE_VIDEO; + if (call->opt.video_cnt && + pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0]))) + { + enabled = PJ_TRUE; } - - } else { - enabled = PJ_TRUE; - media_type = media_types[mi]; } if (enabled) { @@ -1807,6 +1872,12 @@ on_error: return status; } + +/* Create SDP based on the current media channel. Note that, this function + * will not modify the media channel, so when receiving new offer or + * updating media count (via call setting), media channel must be reinit'd + * (using pjsua_media_channel_init()) first before calling this function. + */ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, pj_pool_t *pool, const pjmedia_sdp_session *rem_sdp, @@ -1824,6 +1895,8 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, if (pjsua_get_state() != PJSUA_STATE_RUNNING) return PJ_EBUSY; +#if 0 + // This function should not really change the media channel. if (rem_sdp) { /* If this is a re-offer, let's re-initialize media as remote may * add or remove media @@ -1836,24 +1909,6 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, if (status != PJ_SUCCESS) return status; } - -#if 0 - pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; - pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; - unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); - - sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, - maudidx, &maudcnt); - - if (maudcnt==0) { - /* Expecting audio in the offer */ - if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; - pjsua_media_channel_deinit(call_id); - return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); - } - - call->audio_idx = maudidx[0]; -#endif } else { /* Audio is first in our offer, by convention */ // The audio_idx should not be changed here, as this function may be @@ -1861,6 +1916,7 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, // can be anywhere. //call->audio_idx = 0; } +#endif #if 0 // Since r3512, old-style hold should have got transport, created by @@ -2084,6 +2140,8 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, } #endif + call->rem_offerer = (rem_sdp != NULL); + *p_sdp = sdp; return PJ_SUCCESS; } @@ -2463,8 +2521,10 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, const pj_str_t STR_VIDEO = { "video", 5 }; pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); + unsigned mtotaudcnt = PJ_ARRAY_SIZE(maudidx); pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA]; unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx); + unsigned mtotvidcnt = PJ_ARRAY_SIZE(mvididx); pj_bool_t need_renego_sdp = PJ_FALSE; if (pjsua_get_state() != PJSUA_STATE_RUNNING) @@ -2484,22 +2544,27 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, /* Reset audio_idx first */ call->audio_idx = -1; - /* Apply maximum audio/video count of the account */ + /* Sort audio/video based on "quality" */ sort_media(local_sdp, &STR_AUDIO, acc->cfg.use_srtp, - maudidx, &maudcnt); + maudidx, &maudcnt, &mtotaudcnt); #if PJMEDIA_HAS_VIDEO sort_media(local_sdp, &STR_VIDEO, acc->cfg.use_srtp, - mvididx, &mvidcnt); + mvididx, &mvidcnt, &mtotvidcnt); #else PJ_UNUSED_ARG(STR_VIDEO); mvidcnt = 0; #endif - if (maudcnt > acc->cfg.max_audio_cnt || mvidcnt > acc->cfg.max_video_cnt) + + /* Applying media count limitation. Note that in generating SDP answer, + * no media count limitation applied, as we didn't know yet which media + * would pass the SDP negotiation. + */ + if (maudcnt > call->opt.audio_cnt || mvidcnt > call->opt.video_cnt) { pjmedia_sdp_session *local_sdp2; - maudcnt = PJ_MIN(maudcnt, acc->cfg.max_audio_cnt); - mvidcnt = PJ_MIN(mvidcnt, acc->cfg.max_video_cnt); + maudcnt = PJ_MIN(maudcnt, call->opt.audio_cnt); + mvidcnt = PJ_MIN(mvidcnt, call->opt.video_cnt); local_sdp2 = pjmedia_sdp_session_clone(tmp_pool, local_sdp); for (mi=0; mi < local_sdp2->media_count; ++mi) { diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c index 38b77f22..81b943e1 100644 --- a/pjsip/src/pjsua-lib/pjsua_vid.c +++ b/pjsip/src/pjsua-lib/pjsua_vid.c @@ -1312,6 +1312,10 @@ PJ_DEF(pj_status_t) pjsua_vid_win_set_show( pjsua_vid_win_id wid, return PJ_EINVAL; } + /* Make sure that renderer gets started before shown up */ + if (show && !pjmedia_vid_port_is_running(w->vp_rend)) + status = pjmedia_vid_port_start(w->vp_rend); + hide = !show; status = pjmedia_vid_dev_stream_set_cap(s, PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE, &hide); @@ -1540,17 +1544,12 @@ static pj_status_t call_add_video(pjsua_call *call, pjmedia_sdp_session *sdp; pjmedia_sdp_media *sdp_m; pjmedia_transport_info tpinfo; - unsigned active_cnt; pj_status_t status; /* Verify media slot availability */ if (call->med_cnt == PJSUA_MAX_CALL_MEDIA) return PJ_ETOOMANY; - call_get_vid_strm_info(call, NULL, NULL, &active_cnt, NULL); - if (active_cnt == acc_cfg->max_video_cnt) - return PJ_ETOOMANY; - /* Get active local SDP and clone it */ status = pjmedia_sdp_neg_get_active_local(call->inv->neg, ¤t_sdp); if (status != PJ_SUCCESS) @@ -1617,6 +1616,8 @@ static pj_status_t call_add_video(pjsua_call *call, if (status != PJ_SUCCESS) goto on_error; + call->opt.video_cnt++; + return PJ_SUCCESS; on_error: @@ -1758,6 +1759,7 @@ on_error: /* Deactivate the stream */ pjmedia_sdp_media_deactivate(pool, sdp->media[med_idx]); + call->opt.video_cnt--; } status = call_reoffer_sdp(call->index, sdp); |