summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2011-12-01 09:06:14 +0000
committerNanang Izzuddin <nanang@teluu.com>2011-12-01 09:06:14 +0000
commitfb7ffe37b9ca728f0d3f6bf57b937e114d2f9161 (patch)
treebf3d2bd71b21ee29d72fd4bb99af186d8b18f064
parent9ad8beaa148c78e04a2aac3c5ad6d85567d31b01 (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.c122
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h147
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h8
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c19
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c216
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c1
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c211
-rw-r--r--pjsip/src/pjsua-lib/pjsua_vid.c12
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, &current_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);