diff options
-rw-r--r-- | pjlib/src/pj/config.c | 2 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/conference.c | 67 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/rtp.c | 10 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/stream.c | 12 | ||||
-rw-r--r-- | pjsip/include/pjsip-ua/sip_inv.h | 12 | ||||
-rw-r--r-- | pjsip/src/pjsip-ua/sip_inv.c | 166 | ||||
-rw-r--r-- | pjsip/src/pjsua/pjsua.h | 6 | ||||
-rw-r--r-- | pjsip/src/pjsua/pjsua_inv.c | 63 | ||||
-rw-r--r-- | pjsip/src/pjsua/pjsua_opt.c | 59 |
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; } } |