summaryrefslogtreecommitdiff
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
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
-rw-r--r--pjlib/src/pj/config.c2
-rw-r--r--pjmedia/src/pjmedia/conference.c67
-rw-r--r--pjmedia/src/pjmedia/rtp.c10
-rw-r--r--pjmedia/src/pjmedia/stream.c12
-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
9 files changed, 276 insertions, 121 deletions
diff --git a/pjlib/src/pj/config.c b/pjlib/src/pj/config.c
index cca1362a..2322df99 100644
--- a/pjlib/src/pj/config.c
+++ b/pjlib/src/pj/config.c
@@ -21,7 +21,7 @@
#include <pj/ioqueue.h>
static const char *id = "config.c";
-const char *PJ_VERSION = "0.5.1.1";
+const char *PJ_VERSION = "0.5.1.2";
PJ_DEF(void) pj_dump_config(void)
{
diff --git a/pjmedia/src/pjmedia/conference.c b/pjmedia/src/pjmedia/conference.c
index 8d2d28dc..d851161b 100644
--- a/pjmedia/src/pjmedia/conference.c
+++ b/pjmedia/src/pjmedia/conference.c
@@ -53,6 +53,7 @@ struct conf_port
pjmedia_port *port; /**< get_frame() and put_frame() */
pjmedia_port_op rx_setting; /**< Can we receive from this port */
pjmedia_port_op tx_setting; /**< Can we transmit to this port */
+ int listener_cnt; /**< Number of listeners. */
pj_bool_t *listeners; /**< Array of listeners. */
pjmedia_vad *vad; /**< VAD for this port. */
@@ -467,6 +468,7 @@ PJ_DEF(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf,
if (src_port->listeners[sink_slot] == 0) {
src_port->listeners[sink_slot] = 1;
++conf->connect_cnt;
+ ++src_port->listener_cnt;
if (conf->connect_cnt == 1)
resume_sound(conf);
@@ -505,6 +507,7 @@ PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
if (src_port->listeners[sink_slot] != 0) {
src_port->listeners[sink_slot] = 0;
--conf->connect_cnt;
+ --src_port->listener_cnt;
PJ_LOG(4,(THIS_FILE,"Port %.*s stop transmitting to port %.*s",
(int)src_port->name.slen,
@@ -556,6 +559,7 @@ PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf,
if (conf_port->listeners[port] != 0) {
--conf->connect_cnt;
+ --conf_port->listener_cnt;
conf_port->listeners[port] = 0;
}
}
@@ -563,8 +567,10 @@ PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf,
/* Remove all ports listening from this port. */
conf_port = conf->ports[port];
for (i=0; i<conf->max_ports; ++i) {
- if (conf_port->listeners[i])
+ if (conf_port->listeners[i]) {
--conf->connect_cnt;
+ --conf_port->listener_cnt;
+ }
}
/* Remove the port. */
@@ -693,20 +699,24 @@ static pj_status_t play_cb( /* in */ void *user_data,
}
/* Get frame from this port.
- * If port has rx_buffer, then get the frame from the rx_buffer
- * instead.
+ * If port has rx_buffer (e.g. sound port), then get the frame
+ * from the rx_buffer instead.
*/
- if (i==0/*conf_port->cur_rx_buf*/) {
+ if (i==0) {
pj_int16_t *rx_buf;
- if (conf_port->rx_read == conf_port->rx_write)
- conf_port->rx_read = (conf_port->rx_write+RX_BUF_COUNT-RX_BUF_COUNT/2) % RX_BUF_COUNT;
+ if (conf_port->rx_read == conf_port->rx_write) {
+ conf_port->rx_read =
+ (conf_port->rx_write+RX_BUF_COUNT-RX_BUF_COUNT/2) %
+ RX_BUF_COUNT;
+ }
rx_buf = conf_port->rx_buf[conf_port->rx_read];
for (j=0; j<conf->samples_per_frame; ++j) {
((pj_int16_t*)output)[j] = rx_buf[j];
}
conf_port->rx_read = (conf_port->rx_read+1) % RX_BUF_COUNT;
+
} else {
pjmedia_frame frame;
@@ -714,12 +724,19 @@ static pj_status_t play_cb( /* in */ void *user_data,
frame.buf = output;
frame.size = size;
pjmedia_port_get_frame(conf_port->port, &frame);
+
+ if (frame.type == PJMEDIA_FRAME_TYPE_NONE)
+ continue;
}
/* Skip (after receiving the frame) if this port is muted. */
if (conf_port->rx_setting == PJMEDIA_PORT_MUTE)
continue;
+ /* Also skip if this port doesn't have listeners. */
+ if (conf_port->listener_cnt == 0)
+ continue;
+
/* Do we have signal? */
silence = pjmedia_vad_detect_silence(conf_port->vad,
output,
@@ -727,10 +744,10 @@ static pj_status_t play_cb( /* in */ void *user_data,
&level);
/* Skip if we don't have signal. */
- if (silence) {
- TRACE_(("sil:%d ", i));
- continue;
- }
+ //if (silence) {
+ // TRACE_(("sil:%d ", i));
+ // continue;
+ //}
/* Convert the buffer to unsigned value */
for (j=0; j<conf->samples_per_frame; ++j)
@@ -742,7 +759,7 @@ static pj_status_t play_cb( /* in */ void *user_data,
pj_uint32_t *sum_buf;
unsigned k;
- if (conf_port->listeners[j] == 0)
+ if (listener == 0)
continue;
/* Skip if this listener doesn't want to receive audio */
@@ -768,6 +785,20 @@ static pj_status_t play_cb( /* in */ void *user_data,
if (!conf_port)
continue;
+ if (conf_port->tx_setting == PJMEDIA_PORT_MUTE) {
+ frame.type = PJMEDIA_FRAME_TYPE_NONE;
+ frame.buf = NULL;
+ frame.size = 0;
+
+ if (conf_port->port)
+ pjmedia_port_put_frame(conf_port->port, &frame);
+
+ continue;
+
+ } else if (conf_port->tx_setting != PJMEDIA_PORT_ENABLE) {
+ continue;
+ }
+
//
// TODO:
// When there's no source, not transmit the frame, but instead
@@ -779,10 +810,7 @@ static pj_status_t play_cb( /* in */ void *user_data,
target_buf = (conf_port->cur_tx_buf==conf_port->tx_buf1?
conf_port->tx_buf2 : conf_port->tx_buf1);
- if (!conf_port->sources) {
- for (j=0; j<conf->samples_per_frame; ++j)
- target_buf[j] = 0;
- } else {
+ if (conf_port->sources) {
for (j=0; j<conf->samples_per_frame; ++j) {
target_buf[j] = unsigned2pcm(conf_port->sum_buf[j] / conf_port->sources);
}
@@ -791,11 +819,12 @@ static pj_status_t play_cb( /* in */ void *user_data,
/* Switch buffer. */
conf_port->cur_tx_buf = target_buf;
- if (conf_port->tx_setting != PJMEDIA_PORT_ENABLE)
- continue;
-
pj_memset(&frame, 0, sizeof(frame));
- frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+ if (conf_port->sources)
+ frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+ else
+ frame.type = PJMEDIA_FRAME_TYPE_NONE;
+
frame.buf = conf_port->cur_tx_buf;
frame.size = conf->samples_per_frame * conf->bits_per_sample / 8;
frame.timestamp.u64 = timestamp;
diff --git a/pjmedia/src/pjmedia/rtp.c b/pjmedia/src/pjmedia/rtp.c
index bc87cc95..17b4e712 100644
--- a/pjmedia/src/pjmedia/rtp.c
+++ b/pjmedia/src/pjmedia/rtp.c
@@ -92,9 +92,17 @@ PJ_DEF(pj_status_t) pjmedia_rtp_encode_rtp( pjmedia_rtp_session *ses, int pt, in
"pjmedia_rtp_encode_rtp: ses=%p, pt=%d, m=%d, pt_len=%d, ts_len=%d",
ses, pt, m, payload_len, ts_len));
+ /* Update timestamp */
+ ses->out_hdr.ts = pj_htonl(pj_ntohl(ses->out_hdr.ts)+ts_len);
+
+ /* If payload_len is zero, bail out.
+ * This is a clock frame; we're not really transmitting anything.
+ */
+ if (payload_len == 0)
+ return PJ_SUCCESS;
+
/* Update session. */
ses->out_extseq++;
- ses->out_hdr.ts = pj_htonl(pj_ntohl(ses->out_hdr.ts)+ts_len);
/* Create outgoing header. */
ses->out_hdr.pt = (pj_uint8_t) ((pt == -1) ? ses->out_pt : pt);
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index a5737009..14f46d2b 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -278,7 +278,7 @@ static pj_status_t put_frame( pjmedia_port *port,
(const void**)&rtphdr,
&rtphdrlen);
- } else {
+ } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE) {
unsigned max_size;
max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr);
@@ -296,6 +296,16 @@ static pj_status_t put_frame( pjmedia_port *port,
frame_out.size, ts_len,
(const void**)&rtphdr,
&rtphdrlen);
+ } else {
+
+ /* Just update RTP session's timestamp. */
+ status = pjmedia_rtp_encode_rtp( &channel->rtp,
+ 0, 0,
+ 0, ts_len,
+ (const void**)&rtphdr,
+ &rtphdrlen);
+ return PJ_SUCCESS;
+
}
if (status != 0) {
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;
}
}