summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}
}