diff options
Diffstat (limited to 'pjsip/src/pjsua/pjsua_inv.c')
-rw-r--r-- | pjsip/src/pjsua/pjsua_inv.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/pjsip/src/pjsua/pjsua_inv.c b/pjsip/src/pjsua/pjsua_inv.c new file mode 100644 index 00000000..72272c32 --- /dev/null +++ b/pjsip/src/pjsua/pjsua_inv.c @@ -0,0 +1,331 @@ +/* $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_invite(const char *cstr_dest_uri, + pjsip_inv_session **p_inv) +{ + pj_str_t dest_uri; + pjsip_dialog *dlg; + pjmedia_sdp_session *offer; + pjsip_inv_session *inv; + struct pjsua_inv_data *inv_data; + pjsip_tx_data *tdata; + pj_status_t status; + + /* Convert cstr_dest_uri to dest_uri */ + + dest_uri = pj_str((char*)cstr_dest_uri); + + /* Create outgoing dialog: */ + + status = pjsip_dlg_create_uac( pjsip_ua_instance(), &pjsua.local_uri, + &pjsua.contact_uri, &dest_uri, &dest_uri, + &dlg); + if (status != PJ_SUCCESS) { + pjsua_perror("Dialog creation failed", status); + return status; + } + + /* Get media capability from media endpoint: */ + + status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, + 1, &pjsua.med_skinfo, &offer); + if (status != PJ_SUCCESS) { + pjsua_perror("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("Invite session creation failed", status); + goto on_error; + } + + + /* Create and associate our data in the session. */ + + inv_data = pj_pool_zalloc( dlg->pool, sizeof(struct pjsua_inv_data)); + dlg->mod_data[pjsua.mod.id] = inv_data; + + + /* Set dialog Route-Set: */ + + if (!pj_list_empty(&pjsua.route_set)) + pjsip_dlg_set_route_set(dlg, &pjsua.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("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("Unable to send initial INVITE request", status); + goto on_error; + } + + + /* Done. */ + + *p_inv = inv; + + return PJ_SUCCESS; + + +on_error: + + PJ_TODO(DESTROY_DIALOG_ON_FAIL); + return status; +} + + +/** + * Handle incoming INVITE request. + */ +pj_bool_t pjsua_inv_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; + + /* + * Handle incoming INVITE outside dialog. + */ + if (dlg == NULL && tsx == NULL && + msg->line.req.method.id == PJSIP_INVITE_METHOD) + { + pj_status_t status; + pjsip_tx_data *response = NULL; + unsigned options = 0; + + /* 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); + } + + } else { + /* + * Yes we can handle the incoming INVITE request. + */ + pjsip_inv_session *inv; + struct pjsua_inv_data *inv_data; + pjmedia_sdp_session *answer; + + + /* Get media capability from media endpoint: */ + + status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, + 1, &pjsua.med_skinfo, &answer ); + if (status != PJ_SUCCESS) { + + pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, + NULL, NULL); + return PJ_TRUE; + } + + /* Create dialog: */ + + status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, + &pjsua.contact_uri, &dlg); + if (status != PJ_SUCCESS) + return PJ_TRUE; + + + /* Create invite session: */ + + status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv); + if (status != PJ_SUCCESS) { + + status = pjsip_dlg_create_response( dlg, rdata, 500, NULL, + &response); + if (status == PJ_SUCCESS) + status = pjsip_dlg_send_response(dlg, + pjsip_rdata_get_tsx(rdata), + response); + return PJ_TRUE; + + } + + + /* Create and attach pjsua data to the dialog: */ + + inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data)); + dlg->mod_data[pjsua.mod.id] = inv_data; + + + /* Answer with 100 (using the dialog, not invite): */ + + status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response); + if (status == PJ_SUCCESS) + status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), response); + } + + /* This INVITE request has been handled. */ + return PJ_TRUE; + } + + return PJ_FALSE; +} + + +/* + * This callback receives notification from invite session when the + * session state has changed. + */ +void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) +{ + + /* Destroy media session when invite session is disconnected. */ + if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { + struct pjsua_inv_data *inv_data; + + inv_data = inv->dlg->mod_data[pjsua.mod.id]; + if (inv_data && inv_data->session) { + pjmedia_session_destroy(inv_data->session); + inv_data->session = NULL; + + PJ_LOG(3,(THIS_FILE,"Media session is destroyed")); + } + + } + + pjsua_ui_inv_on_state_changed(inv, e); +} + + +/* + * This callback is called by invite session framework when UAC session + * has forked. + */ +void pjsua_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e) +{ + PJ_UNUSED_ARG(inv); + PJ_UNUSED_ARG(e); + + PJ_TODO(HANDLE_FORKED_DIALOG); +} + + +/* + * 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. + */ +void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status) +{ + struct pjsua_inv_data *inv_data; + const pjmedia_sdp_session *local_sdp; + const pjmedia_sdp_session *remote_sdp; + + if (status != PJ_SUCCESS) { + + pjsua_perror("SDP negotiation has failed", status); + return; + + } + + /* Destroy existing media session, if any. */ + + inv_data = inv->dlg->mod_data[pjsua.mod.id]; + if (inv_data && inv_data->session) { + pjmedia_session_destroy(inv_data->session); + inv_data->session = NULL; + } + + /* Get local and remote SDP */ + + status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp); + if (status != PJ_SUCCESS) { + pjsua_perror("Unable to retrieve currently active local SDP", status); + return; + } + + + status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp); + if (status != PJ_SUCCESS) { + pjsua_perror("Unable to retrieve currently active remote SDP", status); + return; + } + + + /* Create new media session. + * The media session is active immediately. + */ + + if (!pjsua.null_audio) { + + status = pjmedia_session_create( pjsua.med_endpt, 1, &pjsua.med_skinfo, + local_sdp, remote_sdp, + &inv_data->session ); + if (status != PJ_SUCCESS) { + pjsua_perror("Unable to create media session", status); + return; + } + + PJ_LOG(3,(THIS_FILE,"Media has been started successfully")); + } +} |