blob: 6f9607b52cd88b8750c1dad732c581fbf0efa872 [file] [log] [blame]
Benny Prijono84126ab2006-02-09 09:30:09 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include "pjsua.h"
20#include <pj/log.h>
21
22
23/*
24 * pjsua_inv.c
25 *
26 * Invite session specific functionalities.
27 */
28
29#define THIS_FILE "pjsua_inv.c"
30
31
32/**
33 * Make outgoing call.
34 */
35pj_status_t pjsua_invite(const char *cstr_dest_uri,
36 pjsip_inv_session **p_inv)
37{
38 pj_str_t dest_uri;
39 pjsip_dialog *dlg;
40 pjmedia_sdp_session *offer;
41 pjsip_inv_session *inv;
42 struct pjsua_inv_data *inv_data;
43 pjsip_tx_data *tdata;
44 pj_status_t status;
45
46 /* Convert cstr_dest_uri to dest_uri */
47
48 dest_uri = pj_str((char*)cstr_dest_uri);
49
50 /* Create outgoing dialog: */
51
52 status = pjsip_dlg_create_uac( pjsip_ua_instance(), &pjsua.local_uri,
53 &pjsua.contact_uri, &dest_uri, &dest_uri,
54 &dlg);
55 if (status != PJ_SUCCESS) {
56 pjsua_perror("Dialog creation failed", status);
57 return status;
58 }
59
60 /* Get media capability from media endpoint: */
61
62 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool,
63 1, &pjsua.med_skinfo, &offer);
64 if (status != PJ_SUCCESS) {
65 pjsua_perror("pjmedia unable to create SDP", status);
66 goto on_error;
67 }
68
69 /* Create the INVITE session: */
70
71 status = pjsip_inv_create_uac( dlg, offer, 0, &inv);
72 if (status != PJ_SUCCESS) {
73 pjsua_perror("Invite session creation failed", status);
74 goto on_error;
75 }
76
77
78 /* Create and associate our data in the session. */
79
80 inv_data = pj_pool_zalloc( dlg->pool, sizeof(struct pjsua_inv_data));
Benny Prijono632ce712006-02-09 14:01:40 +000081 inv_data->inv = inv;
Benny Prijono84126ab2006-02-09 09:30:09 +000082 dlg->mod_data[pjsua.mod.id] = inv_data;
Benny Prijono834aee32006-02-19 01:38:06 +000083 inv->mod_data[pjsua.mod.id] = inv_data;
Benny Prijono84126ab2006-02-09 09:30:09 +000084
85
86 /* Set dialog Route-Set: */
87
88 if (!pj_list_empty(&pjsua.route_set))
89 pjsip_dlg_set_route_set(dlg, &pjsua.route_set);
90
91
92 /* Set credentials: */
93
94 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,
95 pjsua.cred_info);
96
97
98 /* Create initial INVITE: */
99
100 status = pjsip_inv_invite(inv, &tdata);
101 if (status != PJ_SUCCESS) {
102 pjsua_perror("Unable to create initial INVITE request", status);
103 goto on_error;
104 }
105
106
107 /* Send initial INVITE: */
108
109 status = pjsip_inv_send_msg(inv, tdata, NULL);
110 if (status != PJ_SUCCESS) {
111 pjsua_perror("Unable to send initial INVITE request", status);
112 goto on_error;
113 }
114
Benny Prijono632ce712006-02-09 14:01:40 +0000115 /* Add invite session to the list. */
116
117 pj_list_push_back(&pjsua.inv_list, inv_data);
118
Benny Prijono84126ab2006-02-09 09:30:09 +0000119
120 /* Done. */
121
122 *p_inv = inv;
123
124 return PJ_SUCCESS;
125
126
127on_error:
128
129 PJ_TODO(DESTROY_DIALOG_ON_FAIL);
130 return status;
131}
132
133
134/**
135 * Handle incoming INVITE request.
136 */
137pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata)
138{
139 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
140 pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
141 pjsip_msg *msg = rdata->msg_info.msg;
142
143 /*
144 * Handle incoming INVITE outside dialog.
145 */
146 if (dlg == NULL && tsx == NULL &&
147 msg->line.req.method.id == PJSIP_INVITE_METHOD)
148 {
149 pj_status_t status;
150 pjsip_tx_data *response = NULL;
151 unsigned options = 0;
152
153 /* Verify that we can handle the request. */
154 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
155 pjsua.endpt, &response);
156 if (status != PJ_SUCCESS) {
157
158 /*
159 * No we can't handle the incoming INVITE request.
160 */
161
162 if (response) {
163 pjsip_response_addr res_addr;
164
165 pjsip_get_response_addr(response->pool, rdata, &res_addr);
166 pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,
167 NULL, NULL);
168
169 } else {
170
171 /* Respond with 500 (Internal Server Error) */
172 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
173 NULL, NULL);
174 }
175
176 } else {
177 /*
178 * Yes we can handle the incoming INVITE request.
179 */
180 pjsip_inv_session *inv;
181 struct pjsua_inv_data *inv_data;
182 pjmedia_sdp_session *answer;
183
184
185 /* Get media capability from media endpoint: */
186
187 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool,
188 1, &pjsua.med_skinfo, &answer );
189 if (status != PJ_SUCCESS) {
190
191 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
192 NULL, NULL);
193 return PJ_TRUE;
194 }
195
196 /* Create dialog: */
197
198 status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
199 &pjsua.contact_uri, &dlg);
200 if (status != PJ_SUCCESS)
201 return PJ_TRUE;
202
203
204 /* Create invite session: */
205
206 status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
207 if (status != PJ_SUCCESS) {
208
209 status = pjsip_dlg_create_response( dlg, rdata, 500, NULL,
210 &response);
211 if (status == PJ_SUCCESS)
212 status = pjsip_dlg_send_response(dlg,
213 pjsip_rdata_get_tsx(rdata),
214 response);
215 return PJ_TRUE;
216
217 }
218
219
220 /* Create and attach pjsua data to the dialog: */
221
222 inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data));
Benny Prijono632ce712006-02-09 14:01:40 +0000223 inv_data->inv = inv;
Benny Prijono84126ab2006-02-09 09:30:09 +0000224 dlg->mod_data[pjsua.mod.id] = inv_data;
Benny Prijono834aee32006-02-19 01:38:06 +0000225 inv->mod_data[pjsua.mod.id] = inv_data;
Benny Prijono84126ab2006-02-09 09:30:09 +0000226
Benny Prijono632ce712006-02-09 14:01:40 +0000227 pj_list_push_back(&pjsua.inv_list, inv_data);
228
Benny Prijono84126ab2006-02-09 09:30:09 +0000229
230 /* Answer with 100 (using the dialog, not invite): */
231
232 status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response);
233 if (status == PJ_SUCCESS)
234 status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), response);
235 }
236
237 /* This INVITE request has been handled. */
238 return PJ_TRUE;
239 }
240
241 return PJ_FALSE;
242}
243
244
245/*
246 * This callback receives notification from invite session when the
247 * session state has changed.
248 */
249void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
250{
251
252 /* Destroy media session when invite session is disconnected. */
253 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
254 struct pjsua_inv_data *inv_data;
255
256 inv_data = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono632ce712006-02-09 14:01:40 +0000257
258 pj_assert(inv_data != NULL);
259
Benny Prijono84126ab2006-02-09 09:30:09 +0000260 if (inv_data && inv_data->session) {
261 pjmedia_session_destroy(inv_data->session);
262 inv_data->session = NULL;
263
264 PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
265 }
266
Benny Prijono632ce712006-02-09 14:01:40 +0000267 if (inv_data) {
268
269 pj_list_erase(inv_data);
270
271 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000272 }
273
274 pjsua_ui_inv_on_state_changed(inv, e);
275}
276
277
278/*
279 * This callback is called by invite session framework when UAC session
280 * has forked.
281 */
282void pjsua_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e)
283{
284 PJ_UNUSED_ARG(inv);
285 PJ_UNUSED_ARG(e);
286
287 PJ_TODO(HANDLE_FORKED_DIALOG);
288}
289
290
291/*
292 * Callback to be called when SDP offer/answer negotiation has just completed
293 * in the session. This function will start/update media if negotiation
294 * has succeeded.
295 */
296void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
297{
298 struct pjsua_inv_data *inv_data;
299 const pjmedia_sdp_session *local_sdp;
300 const pjmedia_sdp_session *remote_sdp;
301
302 if (status != PJ_SUCCESS) {
303
304 pjsua_perror("SDP negotiation has failed", status);
305 return;
306
307 }
308
309 /* Destroy existing media session, if any. */
310
311 inv_data = inv->dlg->mod_data[pjsua.mod.id];
312 if (inv_data && inv_data->session) {
313 pjmedia_session_destroy(inv_data->session);
314 inv_data->session = NULL;
315 }
316
317 /* Get local and remote SDP */
318
319 status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
320 if (status != PJ_SUCCESS) {
321 pjsua_perror("Unable to retrieve currently active local SDP", status);
322 return;
323 }
324
325
326 status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
327 if (status != PJ_SUCCESS) {
328 pjsua_perror("Unable to retrieve currently active remote SDP", status);
329 return;
330 }
331
332
333 /* Create new media session.
334 * The media session is active immediately.
335 */
336
337 if (!pjsua.null_audio) {
338
339 status = pjmedia_session_create( pjsua.med_endpt, 1, &pjsua.med_skinfo,
340 local_sdp, remote_sdp,
341 &inv_data->session );
342 if (status != PJ_SUCCESS) {
343 pjsua_perror("Unable to create media session", status);
344 return;
345 }
346
347 PJ_LOG(3,(THIS_FILE,"Media has been started successfully"));
348 }
349}
Benny Prijono834aee32006-02-19 01:38:06 +0000350
351
352/*
353 * Terminate all calls.
354 */
355void pjsua_inv_shutdown()
356{
357 struct pjsua_inv_data *inv_data, *next;
358
359 inv_data = pjsua.inv_list.next;
360 while (inv_data != &pjsua.inv_list) {
361 pjsip_tx_data *tdata;
362
363 next = inv_data->next;
364
365 if (pjsip_inv_end_session(inv_data->inv, 410, NULL, &tdata)==0)
366 pjsip_inv_send_msg(inv_data->inv, tdata, NULL);
367
368 inv_data = next;
369 }
370}
371