summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-02-23 13:49:28 +0000
committerBenny Prijono <bennylp@teluu.com>2006-02-23 13:49:28 +0000
commitbc4d45bb16bb152fcf261ac48e574e184b551bd5 (patch)
tree905516933c9e4e6220b8fa35a3fac1421b50f14b /pjsip
parent6d68baecdefbc8b90749dc7cff8def2a5a88af30 (diff)
Added support for NULL frame in rtp stream, fixed bugs here and there in INVITE (e.g. dont send SDP on 180), and set version to 0.5.1.2
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@223 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/include/pjsip-ua/sip_inv.h12
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c166
-rw-r--r--pjsip/src/pjsua/pjsua.h6
-rw-r--r--pjsip/src/pjsua/pjsua_inv.c63
-rw-r--r--pjsip/src/pjsua/pjsua_opt.c59
5 files changed, 207 insertions, 99 deletions
diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h
index 90d0d5a1..f41a1d94 100644
--- a/pjsip/include/pjsip-ua/sip_inv.h
+++ b/pjsip/include/pjsip-ua/sip_inv.h
@@ -350,6 +350,18 @@ PJ_DECL(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
/**
+ * Create the initial response message for the incoming INVITE request in
+ * rdata with status code st_code and optional status text st_text. Use
+ * #pjsip_answer() to create subsequent response message.
+ */
+PJ_DECL(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
+ pjsip_rx_data *rdata,
+ int st_code,
+ const pj_str_t *st_text,
+ const pjmedia_sdp_session *sdp,
+ pjsip_tx_data **p_tdata);
+
+/**
* Create a response message to the initial INVITE request. This function
* can only be called for the initial INVITE request, as subsequent
* re-INVITE request will be answered automatically.
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index 5ab97345..7d1814a0 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -879,11 +879,15 @@ PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
inv->state == PJSIP_INV_STATE_CONFIRMED,
PJ_EINVALIDOP);
+ /* Lock dialog. */
+ pjsip_dlg_inc_lock(inv->dlg);
+
/* Create the INVITE request. */
status = pjsip_dlg_create_request(inv->dlg, &pjsip_invite_method, -1,
&tdata);
if (status != PJ_SUCCESS)
- return status;
+ goto on_return;
+
/* If this is the first INVITE, then copy the headers from inv_hdr.
* These are the headers parsed from the request URI when the
@@ -920,7 +924,7 @@ PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
if (status != PJ_SUCCESS)
- return status;
+ goto on_return;
tdata->msg->body = create_sdp_body(tdata->pool, offer);
}
@@ -945,7 +949,10 @@ PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
/* Done. */
*p_tdata = tdata;
- return PJ_SUCCESS;
+
+on_return:
+ pjsip_dlg_dec_lock(inv->dlg);
+ return status;
}
@@ -1104,18 +1111,44 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
*/
static pj_status_t process_answer( pjsip_inv_session *inv,
int st_code,
- pjsip_tx_data *tdata )
+ pjsip_tx_data *tdata,
+ const pjmedia_sdp_session *local_sdp)
{
pj_status_t status;
pjmedia_sdp_session *sdp = NULL;
- /* Include SDP for 18x and 2xx response.
- * Also if SDP negotiator is ready, start negotiation.
+ /* If local_sdp is specified, then we MUST NOT have answered the
+ * offer before.
*/
- if (st_code/10 == 18 || st_code/10 == 20) {
+ if (local_sdp && (st_code/100==1 || st_code/100==2)) {
+
+ if (inv->neg == NULL) {
+ status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
+ &inv->neg);
+ } else if (pjmedia_sdp_neg_get_state(inv->neg)==
+ PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
+ {
+ status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
+ local_sdp);
+ } else {
+
+ /* Can not specify local SDP at this state. */
+ pj_assert(0);
+ status = PJMEDIA_SDPNEG_EINSTATE;
+ }
+
+ if (status != PJ_SUCCESS)
+ return status;
+
+ }
+
+
+ /* If SDP negotiator is ready, start negotiation. */
+ if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
pjmedia_sdp_neg_state neg_state;
+ /* Start nego when appropriate. */
neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
PJMEDIA_SDP_NEG_STATE_NULL;
@@ -1133,28 +1166,63 @@ static pj_status_t process_answer( pjsip_inv_session *inv,
status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
}
-
}
-
-
- /* Include SDP when it's available.
+ /* Include SDP when it's available for 2xx and 18x (but not 180) response.
* Subsequent response will include this SDP.
*/
if (sdp) {
tdata->msg->body = create_sdp_body(tdata->pool, sdp);
}
- /* Remove message body if this is a non-2xx final response */
- if (st_code >= 300)
- tdata->msg->body = NULL;
-
return PJ_SUCCESS;
}
/*
+ * Create first response to INVITE
+ */
+PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
+ pjsip_rx_data *rdata,
+ int st_code,
+ const pj_str_t *st_text,
+ const pjmedia_sdp_session *sdp,
+ pjsip_tx_data **p_tdata)
+{
+ pjsip_tx_data *tdata;
+ pj_status_t status;
+
+ /* Verify arguments. */
+ PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
+
+ /* Must have INVITE transaction. */
+ PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
+
+ pjsip_dlg_inc_lock(inv->dlg);
+
+ /* Create response */
+ status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
+ &tdata);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Process SDP in answer */
+ status = process_answer(inv, st_code, tdata, sdp);
+ if (status != PJ_SUCCESS) {
+ pjsip_tx_data_dec_ref(tdata);
+ goto on_return;
+ }
+
+ *p_tdata = tdata;
+
+on_return:
+ pjsip_dlg_dec_lock(inv->dlg);
+ return status;
+}
+
+
+/*
* Answer initial INVITE
* Re-INVITE will be answered automatically, and will not use this function.
*/
@@ -1176,49 +1244,28 @@ PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
/* INVITE transaction MUST have transmitted a response (e.g. 100) */
PJ_ASSERT_RETURN(inv->invite_tsx->last_tx, PJ_EINVALIDOP);
- /* If local_sdp is specified, then we MUST NOT have answered the
- * offer before.
- */
- if (local_sdp && (st_code/100==1 || st_code/100==2)) {
-
- if (inv->neg == NULL) {
- status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
- &inv->neg);
- } else if (pjmedia_sdp_neg_get_state(inv->neg)==
- PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
- {
- status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
- local_sdp);
- } else {
-
- /* Can not specify local SDP at this state. */
- pj_assert(0);
- status = PJMEDIA_SDPNEG_EINSTATE;
- }
-
- if (status != PJ_SUCCESS)
- return status;
- }
-
-
-
+ pjsip_dlg_inc_lock(inv->dlg);
/* Modify last response. */
last_res = inv->invite_tsx->last_tx;
status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
if (status != PJ_SUCCESS)
- return status;
+ goto on_return;
/* Process SDP in answer */
- status = process_answer(inv, st_code, last_res);
- if (status != PJ_SUCCESS)
- return status;
+ status = process_answer(inv, st_code, last_res, local_sdp);
+ if (status != PJ_SUCCESS) {
+ pjsip_tx_data_dec_ref(last_res);
+ goto on_return;
+ }
*p_tdata = last_res;
- return PJ_SUCCESS;
+on_return:
+ pjsip_dlg_dec_lock(inv->dlg);
+ return status;
}
@@ -1466,8 +1513,8 @@ PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
/* Can only do this to send response to original INVITE
* request.
*/
- PJ_ASSERT_RETURN((cseq=pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL)) != NULL &&
- (cseq->cseq == inv->invite_tsx->cseq),
+ PJ_ASSERT_RETURN((cseq=pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL))!=NULL
+ && (cseq->cseq == inv->invite_tsx->cseq),
PJ_EINVALIDOP);
status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
@@ -1624,18 +1671,18 @@ static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
if (tsx->method.id == PJSIP_INVITE_METHOD) {
- if (dlg->role == PJSIP_ROLE_UAC) {
+ /* Keep the initial INVITE transaction. */
+ if (inv->invite_tsx == NULL)
+ inv->invite_tsx = tsx;
- /* Keep the initial INVITE transaction. */
- if (inv->invite_tsx == NULL)
- inv->invite_tsx = tsx;
+ if (dlg->role == PJSIP_ROLE_UAC) {
switch (tsx->state) {
case PJSIP_TSX_STATE_CALLING:
inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
break;
default:
- pj_assert(!"Unexpected state");
+ inv_on_state_calling(inv, e);
break;
}
@@ -1650,7 +1697,8 @@ static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
break;
default:
- pj_assert(!"Unexpected state");
+ inv_on_state_incoming(inv, e);
+ break;
}
}
@@ -1675,6 +1723,10 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
switch (tsx->state) {
+ case PJSIP_TSX_STATE_CALLING:
+ inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
+ break;
+
case PJSIP_TSX_STATE_PROCEEDING:
if (dlg->remote.info->tag.slen) {
@@ -1806,6 +1858,10 @@ static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
switch (tsx->state) {
+ case PJSIP_TSX_STATE_TRYING:
+ inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
+ break;
+
case PJSIP_TSX_STATE_PROCEEDING:
/*
* Transaction sent provisional response.
@@ -2129,7 +2185,7 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
return;
/* Process SDP in the answer */
- status = process_answer(inv, 200, tdata);
+ status = process_answer(inv, 200, tdata, NULL);
if (status != PJ_SUCCESS)
return;
diff --git a/pjsip/src/pjsua/pjsua.h b/pjsip/src/pjsua/pjsua.h
index 81927821..2e430ce9 100644
--- a/pjsip/src/pjsua/pjsua.h
+++ b/pjsip/src/pjsua/pjsua.h
@@ -121,6 +121,10 @@ struct pjsua
char *wav_file; /**< WAV file name to play. */
unsigned wav_slot; /**< WAV player slot in bridge */
+ /* User Agent behaviour: */
+
+ int auto_answer; /**< Automatically answer in calls. */
+
/* Since we support simultaneous calls, we need to have multiple
* RTP sockets.
@@ -178,7 +182,7 @@ struct pjsua
int stun_port2;
- /* Misc: */
+ /* Logging: */
int log_level; /**< Logging verbosity. */
int app_log_level; /**< stdout log verbosity. */
diff --git a/pjsip/src/pjsua/pjsua_inv.c b/pjsip/src/pjsua/pjsua_inv.c
index 83b2bfff..f8b211d3 100644
--- a/pjsip/src/pjsua/pjsua_inv.c
+++ b/pjsip/src/pjsua/pjsua_inv.c
@@ -278,9 +278,13 @@ pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata)
pj_list_push_back(&pjsua.inv_list, inv_data);
- /* Answer with 100 (using the dialog, not invite): */
-
- status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response);
+ /* Must answer with some response to initial INVITE.
+ * If auto-answer flag is set, send 200 straight away, otherwise send 100.
+ */
+
+ status = pjsip_inv_initial_answer(inv, rdata,
+ (pjsua.auto_answer ? 200 : 100),
+ NULL, NULL, &response);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create 100 response", status);
@@ -293,21 +297,32 @@ pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata)
// TODO: Need to delete dialog
} else {
- status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata),
- response);
+ status = pjsip_inv_send_msg(inv, response, NULL);
if (status != PJ_SUCCESS)
pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
}
- PJ_LOG(3,(THIS_FILE,
- "\nIncoming call!!\n"
- "From: %.*s\n"
- "To: %.*s\n"
- "(press 'a' to answer, 'h' to decline)",
- (int)dlg->remote.info_str.slen,
- dlg->remote.info_str.ptr,
- (int)dlg->local.info_str.slen,
- dlg->local.info_str.ptr));
+ if (pjsua.auto_answer < 200) {
+ PJ_LOG(3,(THIS_FILE,
+ "\nIncoming call!!\n"
+ "From: %.*s\n"
+ "To: %.*s\n"
+ "(press 'a' to answer, 'h' to decline)",
+ (int)dlg->remote.info_str.slen,
+ dlg->remote.info_str.ptr,
+ (int)dlg->local.info_str.slen,
+ dlg->local.info_str.ptr));
+ } else {
+ PJ_LOG(3,(THIS_FILE,
+ "Call From:%.*s To:%.*s was answered with %d (%s)",
+ (int)dlg->remote.info_str.slen,
+ dlg->remote.info_str.ptr,
+ (int)dlg->local.info_str.slen,
+ dlg->local.info_str.ptr,
+ pjsua.auto_answer,
+ pjsip_get_status_text(pjsua.auto_answer)->ptr ));
+ }
+
/* This INVITE request has been handled. */
return PJ_TRUE;
}
@@ -766,11 +781,23 @@ void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
return;
}
- /* Connect new call to the sound device port (port zero) in the
- * main conference bridge.
+ /* If auto-play is configured, connect the call to the file player
+ * port
*/
- pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot);
- pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0);
+ if (pjsua.wav_file && inv->role == PJSIP_ROLE_UAS) {
+
+ pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,
+ inv_data->conf_slot);
+
+ } else {
+
+ /* Connect new call to the sound device port (port zero) in the
+ * main conference bridge.
+ */
+ pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot);
+ pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0);
+ }
+
/* Done. */
{
diff --git a/pjsip/src/pjsua/pjsua_opt.c b/pjsip/src/pjsua/pjsua_opt.c
index d40f1de1..52819265 100644
--- a/pjsip/src/pjsua/pjsua_opt.c
+++ b/pjsip/src/pjsua/pjsua_opt.c
@@ -41,49 +41,50 @@ const char *pjsua_inv_state_names[] =
static void usage(void)
{
puts("Usage:");
- puts(" pjsua [options] [sip-url]");
+ puts(" pjsua [options]");
puts("");
puts(" [sip-url] Default URL to invite.");
puts("");
puts("General options:");
+ 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))");
puts(" --app-log-level=N Set log max level for stdout display to N");
- puts(" --help Display this help screen");
- puts(" --version Display version info");
- puts("");
- puts("Media options:");
- puts(" --null-audio Use NULL audio device");
- puts(" --wav-file=file Play WAV file in conference bridge");
puts("");
- //puts("");
- //puts("User Agent options:");
- //puts(" --auto-answer=sec Auto-answer all incoming calls after sec seconds.");
- //puts(" --auto-hangup=sec Auto-hangup all calls after sec seconds.");
+ puts("Authentication options:");
+ puts(" --realm=string Set realm");
+ puts(" --username=string Set authentication username");
+ puts(" --password=string Set authentication password");
puts("");
puts("SIP options:");
- puts(" --local-port=port Set TCP/UDP port");
puts(" --id=url Set the URL of local ID (used in From header)");
puts(" --contact=url Override the Contact information");
puts(" --proxy=url Set the URL of proxy server");
- puts(" --outbound=url Set the URL of outbound proxy server");
+ //puts(" --outbound=url Set the URL of outbound proxy server");
+ puts("");
+ puts("Registration Options:");
puts(" --registrar=url Set the URL of registrar server");
puts(" --reg-timeout=secs Set registration interval to secs (default 3600)");
puts("");
- puts("Authentication options:");
- puts(" --realm=string Set realm");
- puts(" --username=string Set authentication username");
- puts(" --password=string Set authentication password");
- puts("");
- puts("STUN options (all must be specified):");
+ puts("Transport Options:");
+ puts(" --local-port=port Set TCP/UDP port");
puts(" --use-stun1=host[:port]");
puts(" --use-stun2=host[:port] Use STUN and set host name and port of STUN servers");
puts("");
- puts("SIMPLE options (may be specified more than once):");
+ puts("Media Options:");
+ puts(" --null-audio Use NULL audio device");
+ //puts(" --wav-file=file Play WAV file in conference bridge");
+ puts("");
+ puts("Buddy List (can be more than one):");
puts(" --add-buddy url Add the specified URL to the buddy list.");
- //puts(" --offer-x-ms-msg Offer \"x-ms-message\" in outgoing INVITE");
- //puts(" --no-presence Do not subscribe presence of buddies");
+ puts("");
+ puts("User Agent options:");
+ puts(" --auto-answer=code Automatically answer incoming calls with code (e.g. 200)");
+ puts(" --auto-play=file Automatically play WAVE file to incoming calls");
puts("");
fflush(stdout);
}
@@ -198,7 +199,7 @@ pj_status_t pjsua_parse_args(int argc, char *argv[])
OPT_REALM, OPT_USERNAME, OPT_PASSWORD,
OPT_USE_STUN1, OPT_USE_STUN2,
OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
- OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_WAV_FILE};
+ OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY};
struct option long_options[] = {
{ "config-file",1, 0, OPT_CONFIG_FILE},
{ "log-file", 1, 0, OPT_LOG_FILE},
@@ -224,7 +225,7 @@ pj_status_t pjsua_parse_args(int argc, char *argv[])
{ "no-presence", 0, 0, OPT_NO_PRESENCE},
{ "auto-answer",1, 0, OPT_AUTO_ANSWER},
{ "auto-hangup",1, 0, OPT_AUTO_HANGUP},
- { "wav-file", 1, 0, OPT_WAV_FILE},
+ { "auto-play", 1, 0, OPT_AUTO_PLAY},
{ NULL, 0, 0, 0}
};
pj_status_t status;
@@ -409,9 +410,17 @@ pj_status_t pjsua_parse_args(int argc, char *argv[])
pjsua.buddies[pjsua.buddy_cnt++].uri = pj_str(optarg);
break;
- case OPT_WAV_FILE:
+ case OPT_AUTO_PLAY:
pjsua.wav_file = optarg;
break;
+
+ case OPT_AUTO_ANSWER:
+ pjsua.auto_answer = atoi(optarg);
+ if (pjsua.auto_answer < 100 || pjsua.auto_answer > 699) {
+ puts("Error: invalid code in --auto-answer (expecting 100-699");
+ return -1;
+ }
+ break;
}
}