summaryrefslogtreecommitdiff
path: root/pjsip/src/pjsua/pjsua_call.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip/src/pjsua/pjsua_call.c')
-rw-r--r--pjsip/src/pjsua/pjsua_call.c1090
1 files changed, 0 insertions, 1090 deletions
diff --git a/pjsip/src/pjsua/pjsua_call.c b/pjsip/src/pjsua/pjsua_call.c
deleted file mode 100644
index e0a9a0af..00000000
--- a/pjsip/src/pjsua/pjsua_call.c
+++ /dev/null
@@ -1,1090 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include "pjsua.h"
-#include <pj/log.h>
-
-
-/*
- * pjsua_inv.c
- *
- * Invite session specific functionalities.
- */
-
-#define THIS_FILE "pjsua_inv.c"
-
-
-/**
- * Make outgoing call.
- */
-pj_status_t pjsua_make_call(int acc_index,
- const char *cstr_dest_uri,
- int *p_call_index)
-{
- pj_str_t dest_uri;
- pjsip_dialog *dlg;
- pjmedia_sdp_session *offer;
- pjsip_inv_session *inv;
- int call_index = -1;
- pjsip_tx_data *tdata;
- pj_status_t status;
-
- /* Convert cstr_dest_uri to dest_uri */
-
- dest_uri = pj_str((char*)cstr_dest_uri);
-
- /* Find free call slot. */
- for (call_index=0; call_index<pjsua.max_calls; ++call_index) {
- if (pjsua.calls[call_index].inv == NULL)
- break;
- }
-
- if (call_index == pjsua.max_calls) {
- PJ_LOG(3,(THIS_FILE, "Error: too many calls!"));
- return PJ_ETOOMANY;
- }
-
- /* Create outgoing dialog: */
-
- status = pjsip_dlg_create_uac( pjsip_ua_instance(),
- &pjsua.acc[acc_index].local_uri,
- &pjsua.acc[acc_index].contact_uri,
- &dest_uri, &dest_uri,
- &dlg);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Dialog creation failed", status);
- return status;
- }
-
- /* Get media capability from media endpoint: */
-
- status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 1,
- &pjsua.calls[call_index].skinfo,
- &offer);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);
- goto on_error;
- }
-
- /* Create the INVITE session: */
-
- status = pjsip_inv_create_uac( dlg, offer, 0, &inv);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Invite session creation failed", status);
- goto on_error;
- }
-
-
- /* Create and associate our data in the session. */
-
- pjsua.calls[call_index].inv = inv;
-
- dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
- inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
-
-
- /* Set dialog Route-Set: */
-
- if (!pj_list_empty(&pjsua.acc[acc_index].route_set))
- pjsip_dlg_set_route_set(dlg, &pjsua.acc[acc_index].route_set);
-
-
- /* Set credentials: */
-
- pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,
- pjsua.cred_info);
-
-
- /* Create initial INVITE: */
-
- status = pjsip_inv_invite(inv, &tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create initial INVITE request",
- status);
- goto on_error;
- }
-
-
- /* Send initial INVITE: */
-
- status = pjsip_inv_send_msg(inv, tdata, NULL);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",
- status);
- goto on_error;
- }
-
-
- /* Done. */
-
- ++pjsua.call_cnt;
-
- if (p_call_index)
- *p_call_index = call_index;
-
- return PJ_SUCCESS;
-
-
-on_error:
- PJ_TODO(DESTROY_DIALOG_ON_FAIL);
- if (call_index != -1) {
- pjsua.calls[call_index].inv = NULL;
- }
- return status;
-}
-
-
-/**
- * Handle incoming INVITE request.
- */
-pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
-{
- pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
- pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
- pjsip_msg *msg = rdata->msg_info.msg;
- pjsip_tx_data *response = NULL;
- unsigned options = 0;
- pjsip_inv_session *inv;
- int acc_index;
- int call_index = -1;
- pjmedia_sdp_session *answer;
- pj_status_t status;
-
- /* Don't want to handle anything but INVITE */
- if (msg->line.req.method.id != PJSIP_INVITE_METHOD)
- return PJ_FALSE;
-
- /* Don't want to handle anything that's already associated with
- * existing dialog or transaction.
- */
- if (dlg || tsx)
- return PJ_FALSE;
-
-
- /* Verify that we can handle the request. */
- status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
- pjsua.endpt, &response);
- if (status != PJ_SUCCESS) {
-
- /*
- * No we can't handle the incoming INVITE request.
- */
-
- if (response) {
- pjsip_response_addr res_addr;
-
- pjsip_get_response_addr(response->pool, rdata, &res_addr);
- pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,
- NULL, NULL);
-
- } else {
-
- /* Respond with 500 (Internal Server Error) */
- pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
- NULL, NULL);
- }
-
- return PJ_TRUE;
- }
-
-
- /*
- * Yes we can handle the incoming INVITE request.
- */
-
- /* Find free call slot. */
- for (call_index=0; call_index < pjsua.max_calls; ++call_index) {
- if (pjsua.calls[call_index].inv == NULL)
- break;
- }
-
- if (call_index == PJSUA_MAX_CALLS) {
- pjsip_endpt_respond_stateless(pjsua.endpt, rdata,
- PJSIP_SC_BUSY_HERE, NULL,
- NULL, NULL);
- return PJ_TRUE;
- }
-
-
- /* Get media capability from media endpoint: */
-
- status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 1,
- &pjsua.calls[call_index].skinfo,
- &answer );
- if (status != PJ_SUCCESS) {
- pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
- NULL, NULL);
-
- return PJ_TRUE;
- }
-
- /* TODO:
- *
- * Get which account is most likely to be associated with this incoming
- * call. We need the account to find which contact URI to put for
- * the call.
- */
- acc_index = 0;
-
- /* Create dialog: */
-
- status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
- &pjsua.acc[acc_index].contact_uri,
- &dlg);
- if (status != PJ_SUCCESS) {
- pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
- NULL, NULL);
-
- return PJ_TRUE;
- }
-
-
- /* Create invite session: */
-
- status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
- if (status != PJ_SUCCESS) {
-
- pjsip_dlg_respond(dlg, rdata, 500, NULL);
-
- // TODO: Need to delete dialog
- return PJ_TRUE;
- }
-
-
- /* Create and attach pjsua data to the dialog: */
-
- pjsua.calls[call_index].inv = inv;
-
- dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
- inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
-
-
- /* 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);
-
- pjsip_dlg_respond(dlg, rdata, 500, NULL);
-
- // TODO: Need to delete dialog
-
- } else {
- status = pjsip_inv_send_msg(inv, response, NULL);
- if (status != PJ_SUCCESS)
- pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
- }
-
- 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 ));
- }
-
- ++pjsua.call_cnt;
-
- /* This INVITE request has been handled. */
- return PJ_TRUE;
-}
-
-
-/*
- * This callback receives notification from invite session when the
- * session state has changed.
- */
-static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
- pjsip_event *e)
-{
- pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
-
- /* If this is an outgoing INVITE that was created because of
- * REFER/transfer, send NOTIFY to transferer.
- */
- if (call && call->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE) {
- int st_code = -1;
- pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
-
-
- switch (call->inv->state) {
- case PJSIP_INV_STATE_NULL:
- case PJSIP_INV_STATE_CALLING:
- /* Do nothing */
- break;
-
- case PJSIP_INV_STATE_EARLY:
- case PJSIP_INV_STATE_CONNECTING:
- st_code = e->body.tsx_state.tsx->status_code;
- ev_state = PJSIP_EVSUB_STATE_ACTIVE;
- break;
-
- case PJSIP_INV_STATE_CONFIRMED:
- /* When state is confirmed, send the final 200/OK and terminate
- * subscription.
- */
- st_code = e->body.tsx_state.tsx->status_code;
- ev_state = PJSIP_EVSUB_STATE_TERMINATED;
- break;
-
- case PJSIP_INV_STATE_DISCONNECTED:
- st_code = e->body.tsx_state.tsx->status_code;
- ev_state = PJSIP_EVSUB_STATE_TERMINATED;
- break;
- }
-
- if (st_code != -1) {
- pjsip_tx_data *tdata;
- pj_status_t status;
-
- status = pjsip_xfer_notify( call->xfer_sub,
- ev_state, st_code,
- NULL, &tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);
- } else {
- status = pjsip_xfer_send_request(call->xfer_sub, tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);
- }
- }
- }
- }
-
-
- pjsua_ui_inv_on_state_changed(call->index, e);
-
- /* call->inv may be NULL now */
-
- /* Destroy media session when invite session is disconnected. */
- if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
-
- pj_assert(call != NULL);
-
- if (call && call->session) {
- pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
- pjmedia_session_destroy(call->session);
- call->session = NULL;
-
- PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
- }
-
- call->inv = NULL;
- --pjsua.call_cnt;
- }
-}
-
-
-/*
- * Callback called by event framework when the xfer subscription state
- * has changed.
- */
-static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
-{
-
- PJ_UNUSED_ARG(event);
-
- /*
- * We're only interested when subscription is terminated, to
- * clear the xfer_sub member of the inv_data.
- */
- if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
- pjsua_call *call;
-
- call = pjsip_evsub_get_mod_data(sub, pjsua.mod.id);
- if (!call)
- return;
-
- pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL);
- call->xfer_sub = NULL;
-
- PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated"));
- }
-}
-
-
-/*
- * Follow transfer (REFER) request.
- */
-static void on_call_transfered( pjsip_inv_session *inv,
- pjsip_rx_data *rdata )
-{
- pj_status_t status;
- pjsip_tx_data *tdata;
- pjsua_call *existing_call;
- int new_call;
- const pj_str_t str_refer_to = { "Refer-To", 8};
- pjsip_generic_string_hdr *refer_to;
- char *uri;
- struct pjsip_evsub_user xfer_cb;
- pjsip_evsub *sub;
-
- existing_call = inv->dlg->mod_data[pjsua.mod.id];
-
- /* Find the Refer-To header */
- refer_to = (pjsip_generic_string_hdr*)
- pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
-
- if (refer_to == NULL) {
- /* Invalid Request.
- * No Refer-To header!
- */
- PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!"));
- pjsip_dlg_respond( inv->dlg, rdata, 400, NULL);
- return;
- }
-
- PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s",
- (int)inv->dlg->remote.info_str.slen,
- inv->dlg->remote.info_str.ptr,
- (int)refer_to->hvalue.slen,
- refer_to->hvalue.ptr));
-
- /* Init callback */
- pj_memset(&xfer_cb, 0, sizeof(xfer_cb));
- xfer_cb.on_evsub_state = &xfer_on_evsub_state;
-
- /* Create transferee event subscription */
- status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create xfer uas", status);
- pjsip_dlg_respond( inv->dlg, rdata, 500, NULL);
- return;
- }
-
- /* Accept the REFER request, send 200 (OK). */
- pjsip_xfer_accept(sub, rdata, 200, NULL);
-
- /* Create initial NOTIFY request */
- status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
- 100, NULL, &tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status);
- return;
- }
-
- /* Send initial NOTIFY request */
- status = pjsip_xfer_send_request( sub, tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status);
- return;
- }
-
- /* We're cheating here.
- * We need to get a null terminated string from a pj_str_t.
- * So grab the pointer from the hvalue and NULL terminate it, knowing
- * that the NULL position will be occupied by a newline.
- */
- uri = refer_to->hvalue.ptr;
- uri[refer_to->hvalue.slen] = '\0';
-
- /* Now make the outgoing call. */
- status = pjsua_make_call(existing_call->acc_index, uri, &new_call);
- if (status != PJ_SUCCESS) {
-
- /* Notify xferer about the error */
- status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
- 500, NULL, &tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",
- status);
- return;
- }
- status = pjsip_xfer_send_request(sub, tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",
- status);
- return;
- }
- return;
- }
-
- /* Put the server subscription in inv_data.
- * Subsequent state changed in pjsua_inv_on_state_changed() will be
- * reported back to the server subscription.
- */
- pjsua.calls[new_call].xfer_sub = sub;
-
- /* Put the invite_data in the subscription. */
- pjsip_evsub_set_mod_data(sub, pjsua.mod.id, &pjsua.calls[new_call]);
-}
-
-
-/*
- * This callback is called when transaction state has changed in INVITE
- * session. We use this to trap incoming REFER request.
- */
-static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
- pjsip_transaction *tsx,
- pjsip_event *e)
-{
- pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
-
- if (tsx->role==PJSIP_ROLE_UAS &&
- tsx->state==PJSIP_TSX_STATE_TRYING &&
- pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0)
- {
- /*
- * Incoming REFER request.
- */
- on_call_transfered(call->inv, e->body.tsx_state.src.rdata);
- }
-}
-
-
-/*
- * This callback is called by invite session framework when UAC session
- * has forked.
- */
-static void pjsua_call_on_forked( pjsip_inv_session *inv,
- pjsip_event *e)
-{
- PJ_UNUSED_ARG(inv);
- PJ_UNUSED_ARG(e);
-
- PJ_TODO(HANDLE_FORKED_DIALOG);
-}
-
-
-/*
- * Create inactive SDP for call hold.
- */
-static pj_status_t create_inactive_sdp(pjsua_call *call,
- pjmedia_sdp_session **p_answer)
-{
- pj_status_t status;
- pjmedia_sdp_conn *conn;
- pjmedia_sdp_attr *attr;
- pjmedia_sdp_session *sdp;
-
- /* Create new offer */
- status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1,
- &call->skinfo, &sdp);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
- return status;
- }
-
- /* Get SDP media connection line */
- conn = sdp->media[0]->conn;
- if (!conn)
- conn = sdp->conn;
-
- /* Modify address */
- conn->addr = pj_str("0.0.0.0");
-
- /* Remove existing directions attributes */
- pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
- pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
- pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
- pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
-
- /* Add inactive attribute */
- attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL);
- pjmedia_sdp_media_add_attr(sdp->media[0], attr);
-
- *p_answer = sdp;
-
- return status;
-}
-
-/*
- * Called when session received new offer.
- */
-static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
- const pjmedia_sdp_session *offer)
-{
- pjsua_call *call;
- pjmedia_sdp_conn *conn;
- pjmedia_sdp_session *answer;
- pj_bool_t is_remote_active;
- pj_status_t status;
-
- call = inv->dlg->mod_data[pjsua.mod.id];
-
- /*
- * See if remote is offering active media (i.e. not on-hold)
- */
- is_remote_active = PJ_TRUE;
-
- conn = offer->media[0]->conn;
- if (!conn)
- conn = offer->conn;
-
- if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
- pj_strcmp2(&conn->addr, "0")==0)
- {
- is_remote_active = PJ_FALSE;
-
- }
- else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))
- {
- is_remote_active = PJ_FALSE;
- }
-
- PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s",
- (is_remote_active ? "active" : "inactive")));
-
- /* Supply candidate answer */
- if (is_remote_active) {
- status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
- &call->skinfo, &answer);
- } else {
- status = create_inactive_sdp( call, &answer );
- }
-
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
- return;
- }
-
- status = pjsip_inv_set_sdp_answer(call->inv, answer);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to set answer", status);
- return;
- }
-
-}
-
-
-/*
- * Callback to be called when SDP offer/answer negotiation has just completed
- * in the session. This function will start/update media if negotiation
- * has succeeded.
- */
-static void pjsua_call_on_media_update(pjsip_inv_session *inv,
- pj_status_t status)
-{
- pjsua_call *call;
- const pjmedia_sdp_session *local_sdp;
- const pjmedia_sdp_session *remote_sdp;
- pjmedia_port *media_port;
- pj_str_t port_name;
- char tmp[PJSIP_MAX_URL_SIZE];
-
- call = inv->dlg->mod_data[pjsua.mod.id];
-
- if (status != PJ_SUCCESS) {
-
- pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
- return;
-
- }
-
- /* Destroy existing media session, if any. */
-
- if (call && call->session) {
- pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
- pjmedia_session_destroy(call->session);
- call->session = NULL;
- }
-
- /* Get local and remote SDP */
-
- status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE,
- "Unable to retrieve currently active local SDP",
- status);
- return;
- }
-
-
- status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE,
- "Unable to retrieve currently active remote SDP",
- status);
- return;
- }
-
- /* Create new media session.
- * The media session is active immediately.
- */
- if (pjsua.null_audio)
- return;
-
- status = pjmedia_session_create( pjsua.med_endpt, 1,
- &call->skinfo,
- local_sdp, remote_sdp,
- call,
- &call->session );
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create media session",
- status);
- return;
- }
-
-
- /* Get the port interface of the first stream in the session.
- * We need the port interface to add to the conference bridge.
- */
- pjmedia_session_get_port(call->session, 0, &media_port);
-
-
- /*
- * Add the call to conference bridge.
- */
- port_name.ptr = tmp;
- port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
- call->inv->dlg->remote.info->uri,
- tmp, sizeof(tmp));
- if (port_name.slen < 1) {
- port_name = pj_str("call");
- }
- status = pjmedia_conf_add_port( pjsua.mconf, call->inv->pool,
- media_port,
- &port_name,
- &call->conf_slot);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create conference slot",
- status);
- pjmedia_session_destroy(call->session);
- call->session = NULL;
- return;
- }
-
- /* If auto-play is configured, connect the call to the file player
- * port
- */
- if (pjsua.auto_play && pjsua.wav_file &&
- call->inv->role == PJSIP_ROLE_UAS)
- {
-
- pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,
- call->conf_slot);
-
- } else if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) {
-
- pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
- call->conf_slot);
-
- } else if (pjsua.auto_conf) {
-
- int i;
-
- pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot);
- pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0);
-
- for (i=0; i < pjsua.max_calls; ++i) {
-
- if (!pjsua.calls[i].session)
- continue;
-
- pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
- pjsua.calls[i].conf_slot);
- pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot,
- call->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, call->conf_slot);
- pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0);
- }
-
-
- /* Done. */
- {
- struct pjmedia_session_info sess_info;
- char info[80];
- int info_len = 0;
- unsigned i;
-
- pjmedia_session_get_info(call->session, &sess_info);
- for (i=0; i<sess_info.stream_cnt; ++i) {
- int len;
- const char *dir;
- pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
-
- switch (strm_info->dir) {
- case PJMEDIA_DIR_NONE:
- dir = "inactive";
- break;
- case PJMEDIA_DIR_ENCODING:
- dir = "sendonly";
- break;
- case PJMEDIA_DIR_DECODING:
- dir = "recvonly";
- break;
- case PJMEDIA_DIR_ENCODING_DECODING:
- dir = "sendrecv";
- break;
- default:
- dir = "unknown";
- break;
- }
- len = pj_ansi_sprintf( info+info_len,
- ", stream #%d: %.*s (%s)", i,
- (int)strm_info->fmt.encoding_name.slen,
- (int)strm_info->fmt.encoding_name.ptr,
- dir);
- if (len > 0)
- info_len += len;
- }
- PJ_LOG(3,(THIS_FILE,"Media started%s", info));
- }
-}
-
-
-/*
- * Hangup call.
- */
-void pjsua_call_hangup(int call_index, int code)
-{
- pjsua_call *call;
- pj_status_t status;
- pjsip_tx_data *tdata;
-
-
- call = &pjsua.calls[call_index];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- return;
- }
-
- status = pjsip_inv_end_session(call->inv, code, NULL, &tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE,
- "Failed to create end session message",
- status);
- return;
- }
-
- /* pjsip_inv_end_session may return PJ_SUCCESS with NULL
- * as p_tdata when INVITE transaction has not been answered
- * with any provisional responses.
- */
- if (tdata == NULL)
- return;
-
- status = pjsip_inv_send_msg(call->inv, tdata, NULL);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE,
- "Failed to send end session message",
- status);
- return;
- }
-}
-
-
-/*
- * Put call on-Hold.
- */
-void pjsua_call_set_hold(int call_index)
-{
- pjmedia_sdp_session *sdp;
- pjsua_call *call;
- pjsip_tx_data *tdata;
- pj_status_t status;
-
- call = &pjsua.calls[call_index];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- return;
- }
-
- if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
- PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
- return;
- }
-
- status = create_inactive_sdp(call, &sdp);
- if (status != PJ_SUCCESS)
- return;
-
- /* Send re-INVITE with new offer */
- status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
- return;
- }
-
- status = pjsip_inv_send_msg( call->inv, tdata, NULL);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
- return;
- }
-}
-
-
-/*
- * re-INVITE.
- */
-void pjsua_call_reinvite(int call_index)
-{
- pjmedia_sdp_session *sdp;
- pjsip_tx_data *tdata;
- pjsua_call *call;
- pj_status_t status;
-
- call = &pjsua.calls[call_index];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- return;
- }
-
-
- if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
- PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
- return;
- }
-
- /* Create SDP */
- status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
- &call->skinfo, &sdp);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",
- status);
- return;
- }
-
- /* Send re-INVITE with new offer */
- status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
- return;
- }
-
- status = pjsip_inv_send_msg( call->inv, tdata, NULL);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
- return;
- }
-}
-
-
-/*
- * Transfer call.
- */
-void pjsua_call_xfer(int call_index, const char *dest)
-{
- pjsip_evsub *sub;
- pjsip_tx_data *tdata;
- pjsua_call *call;
- pj_str_t tmp;
- pj_status_t status;
-
-
- call = &pjsua.calls[call_index];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- return;
- }
-
- /* Create xfer client subscription.
- * We're not interested in knowing the transfer result, so we
- * put NULL as the callback.
- */
- status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create xfer", status);
- return;
- }
-
- /*
- * Create REFER request.
- */
- status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
- return;
- }
-
- /* Send. */
- status = pjsip_xfer_send_request(sub, tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
- return;
- }
-
- /* For simplicity (that's what this program is intended to be!),
- * leave the original invite session as it is. More advanced application
- * may want to hold the INVITE, or terminate the invite, or whatever.
- */
-}
-
-
-/*
- * Terminate all calls.
- */
-void pjsua_inv_shutdown()
-{
- int i;
-
- for (i=0; i<pjsua.max_calls; ++i) {
- pjsip_tx_data *tdata;
- pjsua_call *call;
-
- if (pjsua.calls[i].inv == NULL)
- continue;
-
- call = &pjsua.calls[i];
-
- if (pjsip_inv_end_session(call->inv, 410, NULL, &tdata)==0) {
- if (tdata)
- pjsip_inv_send_msg(call->inv, tdata, NULL);
- }
- }
-}
-
-
-pj_status_t pjsua_call_init(void)
-{
- /* Initialize invite session callback. */
- pjsip_inv_callback inv_cb;
- pj_status_t status;
-
- pj_memset(&inv_cb, 0, sizeof(inv_cb));
- inv_cb.on_state_changed = &pjsua_call_on_state_changed;
- inv_cb.on_new_session = &pjsua_call_on_forked;
- inv_cb.on_media_update = &pjsua_call_on_media_update;
- inv_cb.on_rx_offer = &pjsua_call_on_rx_offer;
- inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed;
-
-
- /* Initialize invite session module: */
- status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb);
-
- return status;
-}