Added --uas-duration and --uas-refresh option (the later is broken)

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@305 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index a242406..95d1398 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -100,6 +100,8 @@
     pjmedia_sock_info	 skinfo;    /**< Preallocated media sockets.	    */
 
     void		*app_data;  /**< Application data.		    */
+    pj_timer_entry	 refresh_tm;/**< Timer to send re-INVITE.	    */
+    pj_timer_entry	 hangup_tm; /**< Timer to hangup call.		    */
 };
 
 typedef struct pjsua_call pjsua_call;
@@ -196,6 +198,8 @@
 
     /* User Agent behaviour: */
     int		     auto_answer;   /**< Automatically answer in calls.	*/
+    int		     uas_refresh;   /**< Time to re-INVITE.		*/
+    int		     uas_duration;  /**< Max call duration.		*/
 
     /* Account: */
     pj_bool_t	     has_acc;	    /**< Any --id cmdline?		*/
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index b245a49..16823e4 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -29,6 +29,74 @@
 #define THIS_FILE   "pjsua_inv.c"
 
 
+#define REFRESH_CALL_TIMER	0x63
+#define HANGUP_CALL_TIMER	0x64
+
+/* Proto */
+static void schedule_call_timer( pjsua_call *call, pj_timer_entry *e,
+				 int timer_type, int duration );
+
+/*
+ * Timer callback when UAS needs to send re-INVITE to see if remote
+ * is still there.
+ */
+static void call_on_timer(pj_timer_heap_t *ht, pj_timer_entry *e)
+{
+    pjsua_call *call = e->user_data;
+
+    PJ_UNUSED_ARG(ht);
+
+    if (e->id == REFRESH_CALL_TIMER) {
+
+	/* If call is still not connected, hangup. */
+	if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
+	    PJ_LOG(3,(THIS_FILE, "Refresh call timer is called when "
+		      "invite is still not confirmed. Call %d will "
+		      "disconnect.", call->index));
+	    pjsua_call_hangup(call->index);
+	} else {
+	    PJ_LOG(3,(THIS_FILE, "Refreshing call %d", call->index));
+	    schedule_call_timer(call,e,REFRESH_CALL_TIMER,pjsua.uas_refresh);
+	    pjsua_call_reinvite(call->index);
+	}
+
+    } else if (e->id == HANGUP_CALL_TIMER) {
+	PJ_LOG(3,(THIS_FILE, "Call %d duration exceeded, disconnecting call",
+			     call->index));
+	pjsua_call_hangup(call->index);
+
+    }
+}
+
+/*
+ * Schedule call timer.
+ */
+static void schedule_call_timer( pjsua_call *call, pj_timer_entry *e,
+				 int timer_type, int duration )
+{
+    pj_time_val timeout;
+
+    if (duration == 0) {
+	/* Cancel timer. */
+	if (e->id != 0) {
+	    pjsip_endpt_cancel_timer(pjsua.endpt, e);
+	    e->id = 0;
+	}
+
+    } else {
+	/* Schedule timer. */
+	timeout.sec = duration;
+	timeout.msec = 0;
+
+	e->cb = &call_on_timer;
+	e->id = timer_type;
+	e->user_data = call;
+
+	pjsip_endpt_schedule_timer( pjsua.endpt, e, &timeout);
+    }
+}
+
+
 /**
  * Make outgoing call.
  */
@@ -334,6 +402,22 @@
 
     ++pjsua.call_cnt;
 
+    /* Schedule timer to refresh. */
+    if (pjsua.uas_refresh > 0) {
+	schedule_call_timer( &pjsua.calls[call_index], 
+			     &pjsua.calls[call_index].refresh_tm,
+			     REFRESH_CALL_TIMER,
+			     pjsua.uas_refresh);
+    }
+
+    /* Schedule timer to hangup call. */
+    if (pjsua.uas_duration > 0) {
+	schedule_call_timer( &pjsua.calls[call_index], 
+			     &pjsua.calls[call_index].hangup_tm,
+			     HANGUP_CALL_TIMER,
+			     pjsua.uas_duration);
+    }
+
     /* This INVITE request has been handled. */
     return PJ_TRUE;
 }
@@ -418,6 +502,11 @@
 	    PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
 	}
 
+	/* Remove timers. */
+	schedule_call_timer(call, &call->refresh_tm, REFRESH_CALL_TIMER, 0);
+	schedule_call_timer(call, &call->hangup_tm, HANGUP_CALL_TIMER, 0);
+
+	/* Free call */
 	call->inv = NULL;
 	--pjsua.call_cnt;
     }
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index aaf5601..36b6692 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -69,6 +69,10 @@
 		      PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE;
 
 
+    /* Default call settings. */
+    pjsua.uas_refresh = -1;
+    pjsua.uas_duration = -1;
+
     /* Default: do not use STUN: */
     pjsua.stun_port1 = pjsua.stun_port2 = 0;
 
@@ -90,8 +94,11 @@
     }
 
     /* Init call array: */
-    for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i)
+    for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i) {
 	pjsua.calls[i].index = i;
+	pjsua.calls[i].refresh_tm._timer_id = -1;
+	pjsua.calls[i].hangup_tm._timer_id = -1;
+    }
 
     /* Default max nb of calls. */
     pjsua.max_calls = 4;
diff --git a/pjsip/src/pjsua-lib/pjsua_settings.c b/pjsip/src/pjsua-lib/pjsua_settings.c
index 234a594..9ea7de4 100644
--- a/pjsip/src/pjsua-lib/pjsua_settings.c
+++ b/pjsip/src/pjsua-lib/pjsua_settings.c
@@ -101,6 +101,8 @@
     puts  ("User Agent options:");
     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  ("  --uas-refresh=N     Interval in UAS to send re-INVITE (default:-1)");
+    puts  ("  --uas-duration=N    Maximum duration of incoming call (default:-1)");
     puts  ("");
     fflush(stdout);
 }
@@ -225,7 +227,8 @@
 	   OPT_AUTO_CONF,
 	   OPT_PLAY_FILE, OPT_WB, OPT_UWB, OPT_RTP_PORT, OPT_ADD_CODEC,
 	   OPT_COMPLEXITY, OPT_QUALITY,
-	   OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS,
+	   OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, OPT_UAS_REFRESH,
+	   OPT_UAS_DURATION,
     };
     struct pj_getopt_option long_options[] = {
 	{ "config-file",1, 0, OPT_CONFIG_FILE},
@@ -265,6 +268,8 @@
 	{ "next-account",0,0, OPT_NEXT_ACCOUNT},
 	{ "next-cred",	0, 0, OPT_NEXT_CRED},
 	{ "max-calls",	1, 0, OPT_MAX_CALLS},
+	{ "uas-refresh",1, 0, OPT_UAS_REFRESH},
+	{ "uas-duration",1,0, OPT_UAS_DURATION},
 	{ NULL, 0, 0, 0}
     };
     pj_status_t status;
@@ -536,6 +541,22 @@
 		return -1;
 	    }
 	    break;
+
+	case OPT_UAS_REFRESH:
+	    pjsua.uas_refresh = my_atoi(pj_optarg);
+	    if (pjsua.uas_refresh < 1) {
+		PJ_LOG(1,(THIS_FILE,"Invalid value for --uas-refresh (must be >0)"));
+		return -1;
+	    }
+	    break;
+
+	case OPT_UAS_DURATION:
+	    pjsua.uas_duration = my_atoi(pj_optarg);
+	    if (pjsua.uas_duration < 1) {
+		PJ_LOG(1,(THIS_FILE,"Invalid value for --uas-duration (must be >0)"));
+		return -1;
+	    }
+	    break;
 	}
     }
 
@@ -915,6 +936,19 @@
 		    pjsua.max_calls);
     pj_strcat2(&cfg, line);
 
+    /* Uas-refresh. */
+    if (pjsua.uas_refresh > 0) {
+	pj_ansi_sprintf(line, "--uas-refresh %d\n",
+			pjsua.uas_refresh);
+	pj_strcat2(&cfg, line);
+    }
+
+    /* Uas-duration. */
+    if (pjsua.uas_duration > 0) {
+	pj_ansi_sprintf(line, "--uas-duration %d\n",
+			pjsua.uas_duration);
+	pj_strcat2(&cfg, line);
+    }
 
     pj_strcat2(&cfg, "#\n# Buddies:\n#\n");