summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c79
-rw-r--r--pjsip/include/pjsip/sip_msg.h18
-rw-r--r--pjsip/src/pjsip/sip_msg.c33
3 files changed, 117 insertions, 13 deletions
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index 3639b878..2bb7d9d0 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -20,9 +20,16 @@
#define THIS_FILE "pjsua.c"
+#define NO_LIMIT (int)0x7FFFFFFF
//#define STEREO_DEMO
+/* Call specific data */
+struct call_data
+{
+ pj_timer_entry timer;
+};
+
/* Pjsua application data */
static struct app_config
@@ -41,6 +48,8 @@ static struct app_config
unsigned buddy_cnt;
pjsua_buddy_config buddy_cfg[PJSUA_MAX_BUDDIES];
+ struct call_data call_data[PJSUA_MAX_CALLS];
+
pj_pool_t *pool;
/* Compatibility with older pjsua */
@@ -82,11 +91,11 @@ static void usage(void)
puts (" pjsua [options]");
puts ("");
puts ("General options:");
+ puts (" --config-file=file Read the config/arguments from file.");
puts (" --help Display this help screen");
puts (" --version Display version info");
puts ("");
puts ("Logging options:");
- puts (" --config-file=file Read the config/arguments from file.");
puts (" --log-file=fname Log to filename (default stderr)");
puts (" --log-level=N Set log max level to N (0(none) to 6(trace)) (default=5)");
puts (" --app-log-level=N Set log max level for stdout display (default=4)");
@@ -144,9 +153,8 @@ static void usage(void)
puts (" --auto-answer=code Automatically answer incoming calls with code (e.g. 200)");
puts (" --max-calls=N Maximum number of concurrent calls (default:4, max:255)");
puts (" --thread-cnt=N Number of worker threads (default:1)");
- /*
puts (" --duration=SEC Set maximum call duration (default:no limit)");
- */
+
puts ("");
fflush(stdout);
}
@@ -167,7 +175,7 @@ static void default_config(struct app_config *cfg)
cfg->udp_cfg.port = 5060;
pjsua_transport_config_default(&cfg->rtp_cfg);
cfg->rtp_cfg.port = 4000;
- cfg->duration = (unsigned)-1;
+ cfg->duration = NO_LIMIT;
cfg->wav_id = PJSUA_INVALID_ID;
cfg->wav_port = PJSUA_INVALID_ID;
}
@@ -621,11 +629,11 @@ static pj_status_t parse_args(int argc, char *argv[],
return -1;
}
break;
+ */
case OPT_DURATION:
cfg->duration = my_atoi(pj_optarg);
break;
- */
case OPT_THREAD_CNT:
cfg->cfg.thread_cnt = my_atoi(pj_optarg);
@@ -707,7 +715,8 @@ static pj_status_t parse_args(int argc, char *argv[],
case OPT_MAX_CALLS:
cfg->cfg.max_calls = my_atoi(pj_optarg);
if (cfg->cfg.max_calls < 1 || cfg->cfg.max_calls > PJSUA_MAX_CALLS) {
- PJ_LOG(1,(THIS_FILE,"Too many calls for max-calls (1-%d)",
+ PJ_LOG(1,(THIS_FILE,"Error: maximum call setting exceeds "
+ "compile time limit (PJSUA_MAX_CALLS=%d)",
PJSUA_MAX_CALLS));
return -1;
}
@@ -1042,7 +1051,7 @@ static int write_settings(const struct app_config *config,
pj_strcat2(&cfg, line);
/* Uas-duration. */
- if (config->duration != (unsigned)-1) {
+ if (config->duration != NO_LIMIT) {
pj_ansi_sprintf(line, "--duration %d\n",
config->duration);
pj_strcat2(&cfg, line);
@@ -1171,6 +1180,33 @@ static pj_bool_t find_prev_call(void)
}
+/* Callback from timer when the maximum call duration has been
+ * exceeded.
+ */
+static void call_timeout_callback(pj_timer_heap_t *timer_heap,
+ struct pj_timer_entry *entry)
+{
+ pjsua_call_id call_id = entry->id;
+ pjsua_msg_data msg_data;
+ pjsip_generic_string_hdr warn;
+ pj_str_t hname = pj_str("Warning");
+ pj_str_t hvalue = pj_str("399 pjsua \"Call duration exceeded\"");
+
+ PJ_UNUSED_ARG(timer_heap);
+
+ /* Add warning header */
+ pjsua_msg_data_init(&msg_data);
+ pjsip_generic_string_hdr_init2(&warn, &hname, &hvalue);
+ pj_list_push_back(&msg_data.hdr_list, &warn);
+
+ /* Call duration has been exceeded; disconnect the call */
+ PJ_LOG(3,(THIS_FILE, "Duration (%d seconds) has been exceeded "
+ "for call %d, disconnecting the call",
+ app_config.duration, call_id));
+ entry->id = PJSUA_INVALID_ID;
+ pjsua_call_hangup(call_id, 200, NULL, &msg_data);
+}
+
/*
* Handler when invite state has changed.
@@ -1185,6 +1221,15 @@ static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
if (call_info.state == PJSIP_INV_STATE_DISCONNECTED) {
+ /* Cancel duration timer, if any */
+ if (app_config.call_data[call_id].timer.id != PJSUA_INVALID_ID) {
+ struct call_data *cd = &app_config.call_data[call_id];
+ pjsip_endpoint *endpt = pjsua_get_pjsip_endpt();
+
+ cd->timer.id = PJSUA_INVALID_ID;
+ pjsip_endpt_cancel_timer(endpt, &cd->timer);
+ }
+
PJ_LOG(3,(THIS_FILE, "Call %d is DISCONNECTED [reason=%d (%s)]",
call_id,
call_info.last_status,
@@ -1196,6 +1241,20 @@ static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
} else {
+ if (app_config.duration!=NO_LIMIT &&
+ call_info.state == PJSIP_INV_STATE_CONFIRMED)
+ {
+ /* Schedule timer to hangup call after the specified duration */
+ struct call_data *cd = &app_config.call_data[call_id];
+ pjsip_endpoint *endpt = pjsua_get_pjsip_endpt();
+ pj_time_val delay;
+
+ cd->timer.id = call_id;
+ delay.sec = app_config.duration;
+ delay.msec = 0;
+ pjsip_endpt_schedule_timer(endpt, &cd->timer, &delay);
+ }
+
PJ_LOG(3,(THIS_FILE, "Call %d state changed to %s",
call_id,
call_info.state_text.ptr));
@@ -2364,6 +2423,12 @@ pj_status_t app_init(int argc, char *argv[])
stereo_demo();
#endif
+ /* Initialize calls data */
+ for (i=0; i<PJ_ARRAY_SIZE(app_config.call_data); ++i) {
+ app_config.call_data[i].timer.id = PJSUA_INVALID_ID;
+ app_config.call_data[i].timer.cb = &call_timeout_callback;
+ }
+
/* Optionally registers WAV file */
if (app_config.wav_file.slen) {
status = pjsua_player_create(&app_config.wav_file, 0,
diff --git a/pjsip/include/pjsip/sip_msg.h b/pjsip/include/pjsip/sip_msg.h
index af7ad922..08f8e88e 100644
--- a/pjsip/include/pjsip/sip_msg.h
+++ b/pjsip/include/pjsip/sip_msg.h
@@ -879,6 +879,7 @@ pjsip_generic_string_hdr_create( pj_pool_t *pool,
const pj_str_t *hname,
const pj_str_t *hvalue);
+
/**
* Initialize a preallocated memory with the header structure. This function
* should only be called when application uses its own memory allocation to
@@ -903,6 +904,23 @@ pjsip_generic_string_hdr_init( pj_pool_t *pool,
const pj_str_t *hvalue);
+/**
+ * Construct a generic string header without allocating memory from the pool.
+ * This function is useful to create a temporary header which life-time is
+ * very short (for example, creating the header in the stack to be passed
+ * as argument to a function which will copy the header).
+ *
+ * @param pool The pool.
+ * @param hname The header name to be assigned to the header, or NULL to
+ * assign the header name with some string.
+ * @param hvalue Optional string to be assigned as the value.
+ *
+ * @return The header, or THROW exception.
+ */
+PJ_DECL(void) pjsip_generic_string_hdr_init2(pjsip_generic_string_hdr *h,
+ pj_str_t *hname,
+ pj_str_t *hvalue);
+
/* **************************************************************************/
diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c
index d5eb1009..1e4c5729 100644
--- a/pjsip/src/pjsip/sip_msg.c
+++ b/pjsip/src/pjsip/sip_msg.c
@@ -505,6 +505,25 @@ static pjsip_hdr_vptr generic_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_generic_string_hdr_print,
};
+
+PJ_DEF(void) pjsip_generic_string_hdr_init2(pjsip_generic_string_hdr *hdr,
+ pj_str_t *hname,
+ pj_str_t *hvalue)
+{
+ init_hdr(hdr, PJSIP_H_OTHER, &generic_hdr_vptr);
+ if (hname) {
+ hdr->name = *hname;
+ hdr->sname = *hname;
+ }
+ if (hvalue) {
+ hdr->hvalue = *hvalue;
+ } else {
+ hdr->hvalue.ptr = NULL;
+ hdr->hvalue.slen = 0;
+ }
+}
+
+
PJ_DEF(pjsip_generic_string_hdr*)
pjsip_generic_string_hdr_init( pj_pool_t *pool,
void *mem,
@@ -512,19 +531,21 @@ pjsip_generic_string_hdr_init( pj_pool_t *pool,
const pj_str_t *hvalue)
{
pjsip_generic_string_hdr *hdr = mem;
+ pj_str_t dup_hname, dup_hval;
- init_hdr(hdr, PJSIP_H_OTHER, &generic_hdr_vptr);
if (hnames) {
- pj_strdup(pool, &hdr->name, hnames);
- hdr->sname = hdr->name;
+ pj_strdup(pool, &dup_hname, hnames);
+ } else {
+ dup_hname.slen = 0;
}
+
if (hvalue) {
- pj_strdup(pool, &hdr->hvalue, hvalue);
+ pj_strdup(pool, &dup_hval, hvalue);
} else {
- hdr->hvalue.ptr = NULL;
- hdr->hvalue.slen = 0;
+ dup_hval.slen = 0;
}
+ pjsip_generic_string_hdr_init2(hdr, &dup_hname, &dup_hval);
return hdr;
}