blob: f8b211d3c31b466855d34d4b95ea06080a009447 [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,
Benny Prijono26ff9062006-02-21 23:47:00 +000036 struct pjsua_inv_data **p_inv_data)
Benny Prijono84126ab2006-02-09 09:30:09 +000037{
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;
Benny Prijonof04ffdd2006-02-21 00:11:18 +000044 int med_sk_index = 0;
Benny Prijono84126ab2006-02-09 09:30:09 +000045 pj_status_t status;
46
47 /* Convert cstr_dest_uri to dest_uri */
48
49 dest_uri = pj_str((char*)cstr_dest_uri);
50
Benny Prijonof04ffdd2006-02-21 00:11:18 +000051 /* Find free socket. */
52 for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) {
53 if (!pjsua.med_sock_use[med_sk_index])
54 break;
55 }
56
57 if (med_sk_index == PJSUA_MAX_CALLS) {
58 PJ_LOG(3,(THIS_FILE, "Error: too many calls!"));
59 return PJ_ETOOMANY;
60 }
61
62 pjsua.med_sock_use[med_sk_index] = 1;
63
Benny Prijono84126ab2006-02-09 09:30:09 +000064 /* Create outgoing dialog: */
65
66 status = pjsip_dlg_create_uac( pjsip_ua_instance(), &pjsua.local_uri,
67 &pjsua.contact_uri, &dest_uri, &dest_uri,
68 &dlg);
69 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +000070 pjsua_perror(THIS_FILE, "Dialog creation failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +000071 return status;
72 }
73
74 /* Get media capability from media endpoint: */
75
76 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool,
Benny Prijonof04ffdd2006-02-21 00:11:18 +000077 1, &pjsua.med_sock_info[med_sk_index],
78 &offer);
Benny Prijono84126ab2006-02-09 09:30:09 +000079 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +000080 pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);
Benny Prijono84126ab2006-02-09 09:30:09 +000081 goto on_error;
82 }
83
84 /* Create the INVITE session: */
85
86 status = pjsip_inv_create_uac( dlg, offer, 0, &inv);
87 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +000088 pjsua_perror(THIS_FILE, "Invite session creation failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +000089 goto on_error;
90 }
91
92
93 /* Create and associate our data in the session. */
94
95 inv_data = pj_pool_zalloc( dlg->pool, sizeof(struct pjsua_inv_data));
Benny Prijono632ce712006-02-09 14:01:40 +000096 inv_data->inv = inv;
Benny Prijonof04ffdd2006-02-21 00:11:18 +000097 inv_data->call_slot = med_sk_index;
Benny Prijono84126ab2006-02-09 09:30:09 +000098 dlg->mod_data[pjsua.mod.id] = inv_data;
Benny Prijono834aee32006-02-19 01:38:06 +000099 inv->mod_data[pjsua.mod.id] = inv_data;
Benny Prijono84126ab2006-02-09 09:30:09 +0000100
101
102 /* Set dialog Route-Set: */
103
104 if (!pj_list_empty(&pjsua.route_set))
105 pjsip_dlg_set_route_set(dlg, &pjsua.route_set);
106
107
108 /* Set credentials: */
109
110 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,
111 pjsua.cred_info);
112
113
114 /* Create initial INVITE: */
115
116 status = pjsip_inv_invite(inv, &tdata);
117 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000118 pjsua_perror(THIS_FILE, "Unable to create initial INVITE request",
119 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000120 goto on_error;
121 }
122
123
124 /* Send initial INVITE: */
125
126 status = pjsip_inv_send_msg(inv, tdata, NULL);
127 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000128 pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",
129 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000130 goto on_error;
131 }
132
Benny Prijono632ce712006-02-09 14:01:40 +0000133 /* Add invite session to the list. */
134
135 pj_list_push_back(&pjsua.inv_list, inv_data);
136
Benny Prijono84126ab2006-02-09 09:30:09 +0000137
138 /* Done. */
Benny Prijono26ff9062006-02-21 23:47:00 +0000139 if (p_inv_data)
140 *p_inv_data = inv_data;
Benny Prijono84126ab2006-02-09 09:30:09 +0000141
142 return PJ_SUCCESS;
143
144
145on_error:
146
147 PJ_TODO(DESTROY_DIALOG_ON_FAIL);
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000148 pjsua.med_sock_use[med_sk_index] = 0;
Benny Prijono84126ab2006-02-09 09:30:09 +0000149 return status;
150}
151
152
153/**
154 * Handle incoming INVITE request.
155 */
156pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata)
157{
158 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
159 pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
160 pjsip_msg *msg = rdata->msg_info.msg;
Benny Prijono26ff9062006-02-21 23:47:00 +0000161 pjsip_tx_data *response = NULL;
162 unsigned options = 0;
163 pjsip_inv_session *inv;
164 struct pjsua_inv_data *inv_data;
165 pjmedia_sdp_session *answer;
166 int med_sk_index;
167 pj_status_t status;
Benny Prijono84126ab2006-02-09 09:30:09 +0000168
Benny Prijono26ff9062006-02-21 23:47:00 +0000169 /* Don't want to handle anything but INVITE */
170 if (msg->line.req.method.id != PJSIP_INVITE_METHOD)
171 return PJ_FALSE;
172
173 /* Don't want to handle anything that's already associated with
174 * existing dialog or transaction.
Benny Prijono84126ab2006-02-09 09:30:09 +0000175 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000176 if (dlg || tsx)
177 return PJ_FALSE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000178
Benny Prijono84126ab2006-02-09 09:30:09 +0000179
Benny Prijono26ff9062006-02-21 23:47:00 +0000180 /* Verify that we can handle the request. */
181 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
182 pjsua.endpt, &response);
183 if (status != PJ_SUCCESS) {
Benny Prijono84126ab2006-02-09 09:30:09 +0000184
Benny Prijono26ff9062006-02-21 23:47:00 +0000185 /*
186 * No we can't handle the incoming INVITE request.
187 */
Benny Prijono84126ab2006-02-09 09:30:09 +0000188
Benny Prijono26ff9062006-02-21 23:47:00 +0000189 if (response) {
190 pjsip_response_addr res_addr;
Benny Prijono84126ab2006-02-09 09:30:09 +0000191
Benny Prijono26ff9062006-02-21 23:47:00 +0000192 pjsip_get_response_addr(response->pool, rdata, &res_addr);
193 pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,
194 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000195
196 } else {
Benny Prijono84126ab2006-02-09 09:30:09 +0000197
Benny Prijono26ff9062006-02-21 23:47:00 +0000198 /* Respond with 500 (Internal Server Error) */
199 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
200 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000201 }
202
Benny Prijono26ff9062006-02-21 23:47:00 +0000203 return PJ_TRUE;
204 }
205
206
207 /*
208 * Yes we can handle the incoming INVITE request.
209 */
210
211 /* Find free call slot. */
212 for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) {
213 if (!pjsua.med_sock_use[med_sk_index])
214 break;
215 }
216
217 if (med_sk_index == PJSUA_MAX_CALLS) {
218 pjsip_endpt_respond_stateless(pjsua.endpt, rdata,
219 PJSIP_SC_BUSY_HERE, NULL,
220 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000221 return PJ_TRUE;
222 }
223
Benny Prijono26ff9062006-02-21 23:47:00 +0000224
225 pjsua.med_sock_use[med_sk_index] = 1;
226
227 /* Get media capability from media endpoint: */
228
229 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool,
230 1, &pjsua.med_sock_info[med_sk_index],
231 &answer );
232 if (status != PJ_SUCCESS) {
233 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
234 NULL, NULL);
235
236 /* Free call socket. */
237 pjsua.med_sock_use[med_sk_index] = 0;
238 return PJ_TRUE;
239 }
240
241 /* Create dialog: */
242
243 status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
244 &pjsua.contact_uri, &dlg);
245 if (status != PJ_SUCCESS) {
246 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
247 NULL, NULL);
248
249 /* Free call socket. */
250 pjsua.med_sock_use[med_sk_index] = 0;
251 return PJ_TRUE;
252 }
253
254
255 /* Create invite session: */
256
257 status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
258 if (status != PJ_SUCCESS) {
259
260 pjsip_dlg_respond(dlg, rdata, 500, NULL);
261
262 /* Free call socket. */
263 pjsua.med_sock_use[med_sk_index] = 0;
264
265 // TODO: Need to delete dialog
266 return PJ_TRUE;
267 }
268
269
270 /* Create and attach pjsua data to the dialog: */
271
272 inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data));
273 inv_data->inv = inv;
274 inv_data->call_slot = inv_data->call_slot = med_sk_index;
275 dlg->mod_data[pjsua.mod.id] = inv_data;
276 inv->mod_data[pjsua.mod.id] = inv_data;
277
278 pj_list_push_back(&pjsua.inv_list, inv_data);
279
280
Benny Prijono64f851e2006-02-23 13:49:28 +0000281 /* Must answer with some response to initial INVITE.
282 * If auto-answer flag is set, send 200 straight away, otherwise send 100.
283 */
284
285 status = pjsip_inv_initial_answer(inv, rdata,
286 (pjsua.auto_answer ? 200 : 100),
287 NULL, NULL, &response);
Benny Prijono26ff9062006-02-21 23:47:00 +0000288 if (status != PJ_SUCCESS) {
289
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000290 pjsua_perror(THIS_FILE, "Unable to create 100 response", status);
291
Benny Prijono26ff9062006-02-21 23:47:00 +0000292 pjsip_dlg_respond(dlg, rdata, 500, NULL);
293
294 /* Free call socket. */
295 pjsua.med_sock_use[med_sk_index] = 0;
296
297 // TODO: Need to delete dialog
298
299 } else {
Benny Prijono64f851e2006-02-23 13:49:28 +0000300 status = pjsip_inv_send_msg(inv, response, NULL);
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000301 if (status != PJ_SUCCESS)
302 pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
Benny Prijono26ff9062006-02-21 23:47:00 +0000303 }
304
Benny Prijono64f851e2006-02-23 13:49:28 +0000305 if (pjsua.auto_answer < 200) {
306 PJ_LOG(3,(THIS_FILE,
307 "\nIncoming call!!\n"
308 "From: %.*s\n"
309 "To: %.*s\n"
310 "(press 'a' to answer, 'h' to decline)",
311 (int)dlg->remote.info_str.slen,
312 dlg->remote.info_str.ptr,
313 (int)dlg->local.info_str.slen,
314 dlg->local.info_str.ptr));
315 } else {
316 PJ_LOG(3,(THIS_FILE,
317 "Call From:%.*s To:%.*s was answered with %d (%s)",
318 (int)dlg->remote.info_str.slen,
319 dlg->remote.info_str.ptr,
320 (int)dlg->local.info_str.slen,
321 dlg->local.info_str.ptr,
322 pjsua.auto_answer,
323 pjsip_get_status_text(pjsua.auto_answer)->ptr ));
324 }
325
Benny Prijono26ff9062006-02-21 23:47:00 +0000326 /* This INVITE request has been handled. */
327 return PJ_TRUE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000328}
329
330
331/*
332 * This callback receives notification from invite session when the
333 * session state has changed.
334 */
335void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
336{
Benny Prijono26ff9062006-02-21 23:47:00 +0000337 struct pjsua_inv_data *inv_data;
338
339 inv_data = inv->dlg->mod_data[pjsua.mod.id];
340
341 /* If this is an outgoing INVITE that was created because of
342 * REFER/transfer, send NOTIFY to transferer.
343 */
344 if (inv_data && inv_data->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE)
345 {
346 int st_code = -1;
347 pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
348
349
350 switch (inv->state) {
351 case PJSIP_INV_STATE_NULL:
352 case PJSIP_INV_STATE_CALLING:
353 /* Do nothing */
354 break;
355
356 case PJSIP_INV_STATE_EARLY:
357 case PJSIP_INV_STATE_CONNECTING:
358 st_code = e->body.tsx_state.tsx->status_code;
359 ev_state = PJSIP_EVSUB_STATE_ACTIVE;
360 break;
361
362 case PJSIP_INV_STATE_CONFIRMED:
363 /* When state is confirmed, send the final 200/OK and terminate
364 * subscription.
365 */
366 st_code = e->body.tsx_state.tsx->status_code;
367 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
368 break;
369
370 case PJSIP_INV_STATE_DISCONNECTED:
371 st_code = e->body.tsx_state.tsx->status_code;
372 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
373 break;
374 }
375
376 if (st_code != -1) {
377 pjsip_tx_data *tdata;
378 pj_status_t status;
379
380 status = pjsip_xfer_notify( inv_data->xfer_sub,
381 ev_state, st_code,
382 NULL, &tdata);
383 if (status != PJ_SUCCESS) {
384 pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);
385 } else {
386 status = pjsip_xfer_send_request(inv_data->xfer_sub, tdata);
387 if (status != PJ_SUCCESS) {
388 pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);
389 }
390 }
391 }
392 }
393
Benny Prijono84126ab2006-02-09 09:30:09 +0000394
395 /* Destroy media session when invite session is disconnected. */
396 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono632ce712006-02-09 14:01:40 +0000397
398 pj_assert(inv_data != NULL);
399
Benny Prijono84126ab2006-02-09 09:30:09 +0000400 if (inv_data && inv_data->session) {
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000401 pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot);
Benny Prijono84126ab2006-02-09 09:30:09 +0000402 pjmedia_session_destroy(inv_data->session);
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000403 pjsua.med_sock_use[inv_data->call_slot] = 0;
Benny Prijono84126ab2006-02-09 09:30:09 +0000404 inv_data->session = NULL;
405
406 PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
407 }
408
Benny Prijono632ce712006-02-09 14:01:40 +0000409 if (inv_data) {
410
411 pj_list_erase(inv_data);
412
413 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000414 }
415
416 pjsua_ui_inv_on_state_changed(inv, e);
417}
418
419
420/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000421 * Callback called by event framework when the xfer subscription state
422 * has changed.
423 */
424static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
425{
426
427 PJ_UNUSED_ARG(event);
428
429 /*
430 * We're only interested when subscription is terminated, to
431 * clear the xfer_sub member of the inv_data.
432 */
433 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
434 struct pjsua_inv_data *inv_data;
435
436 inv_data = pjsip_evsub_get_mod_data(sub, pjsua.mod.id);
437 if (!inv_data)
438 return;
439
440 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL);
441 inv_data->xfer_sub = NULL;
442
443 PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated"));
444 }
445}
446
447
448/*
449 * Follow transfer (REFER) request.
450 */
451static void on_call_transfered( pjsip_inv_session *inv,
452 pjsip_rx_data *rdata )
453{
454 pj_status_t status;
455 pjsip_tx_data *tdata;
456 struct pjsua_inv_data *inv_data;
457 const pj_str_t str_refer_to = { "Refer-To", 8};
458 pjsip_generic_string_hdr *refer_to;
459 char *uri;
460 struct pjsip_evsub_user xfer_cb;
461 pjsip_evsub *sub;
462
463 /* Find the Refer-To header */
464 refer_to = (pjsip_generic_string_hdr*)
465 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
466
467 if (refer_to == NULL) {
468 /* Invalid Request.
469 * No Refer-To header!
470 */
471 PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!"));
472 pjsip_dlg_respond( inv->dlg, rdata, 400, NULL);
473 return;
474 }
475
476 PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s",
477 (int)inv->dlg->remote.info_str.slen,
478 inv->dlg->remote.info_str.ptr,
479 (int)refer_to->hvalue.slen,
480 refer_to->hvalue.ptr));
481
482 /* Init callback */
483 pj_memset(&xfer_cb, 0, sizeof(xfer_cb));
484 xfer_cb.on_evsub_state = &xfer_on_evsub_state;
485
486 /* Create transferee event subscription */
487 status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
488 if (status != PJ_SUCCESS) {
489 pjsua_perror(THIS_FILE, "Unable to create xfer uas", status);
490 pjsip_dlg_respond( inv->dlg, rdata, 500, NULL);
491 return;
492 }
493
494 /* Accept the REFER request, send 200 (OK). */
495 pjsip_xfer_accept(sub, rdata, 200, NULL);
496
497 /* Create initial NOTIFY request */
498 status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
499 100, NULL, &tdata);
500 if (status != PJ_SUCCESS) {
501 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status);
502 return;
503 }
504
505 /* Send initial NOTIFY request */
506 status = pjsip_xfer_send_request( sub, tdata);
507 if (status != PJ_SUCCESS) {
508 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status);
509 return;
510 }
511
512 /* We're cheating here.
513 * We need to get a null terminated string from a pj_str_t.
514 * So grab the pointer from the hvalue and NULL terminate it, knowing
515 * that the NULL position will be occupied by a newline.
516 */
517 uri = refer_to->hvalue.ptr;
518 uri[refer_to->hvalue.slen] = '\0';
519
520 /* Now make the outgoing call. */
521 status = pjsua_invite(uri, &inv_data);
522 if (status != PJ_SUCCESS) {
523
524 /* Notify xferer about the error */
525 status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
526 500, NULL, &tdata);
527 if (status != PJ_SUCCESS) {
528 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",
529 status);
530 return;
531 }
532 status = pjsip_xfer_send_request(sub, tdata);
533 if (status != PJ_SUCCESS) {
534 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",
535 status);
536 return;
537 }
538 return;
539 }
540
541 /* Put the server subscription in inv_data.
542 * Subsequent state changed in pjsua_inv_on_state_changed() will be
543 * reported back to the server subscription.
544 */
545 inv_data->xfer_sub = sub;
546
547 /* Put the invite_data in the subscription. */
548 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, inv_data);
549}
550
551
552/*
553 * This callback is called when transaction state has changed in INVITE
554 * session. We use this to trap incoming REFER request.
555 */
556void pjsua_inv_on_tsx_state_changed(pjsip_inv_session *inv,
557 pjsip_transaction *tsx,
558 pjsip_event *e)
559{
560 if (tsx->role==PJSIP_ROLE_UAS &&
561 tsx->state==PJSIP_TSX_STATE_TRYING &&
562 pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0)
563 {
564 /*
565 * Incoming REFER request.
566 */
567 on_call_transfered(inv, e->body.tsx_state.src.rdata);
568 }
569}
570
571
572/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000573 * This callback is called by invite session framework when UAC session
574 * has forked.
575 */
576void pjsua_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e)
577{
578 PJ_UNUSED_ARG(inv);
579 PJ_UNUSED_ARG(e);
580
581 PJ_TODO(HANDLE_FORKED_DIALOG);
582}
583
584
585/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000586 * Create inactive SDP for call hold.
587 */
588static pj_status_t create_inactive_sdp(struct pjsua_inv_data *inv_session,
589 pjmedia_sdp_session **p_answer)
590{
591 pj_status_t status;
592 pjmedia_sdp_conn *conn;
593 pjmedia_sdp_attr *attr;
594 pjmedia_sdp_session *sdp;
595
596 /* Create new offer */
597 status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1,
598 &pjsua.med_sock_info[inv_session->call_slot],
599 &sdp);
600 if (status != PJ_SUCCESS) {
601 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
602 return status;
603 }
604
605 /* Get SDP media connection line */
606 conn = sdp->media[0]->conn;
607 if (!conn)
608 conn = sdp->conn;
609
610 /* Modify address */
611 conn->addr = pj_str("0.0.0.0");
612
613 /* Remove existing directions attributes */
614 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
615 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
616 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
617 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
618
619 /* Add inactive attribute */
620 attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL);
621 pjmedia_sdp_media_add_attr(sdp->media[0], attr);
622
623 *p_answer = sdp;
624
625 return status;
626}
627
628/*
629 * Called when session received new offer.
630 */
631void pjsua_inv_on_rx_offer( pjsip_inv_session *inv,
632 const pjmedia_sdp_session *offer)
633{
634 struct pjsua_inv_data *inv_data;
635 pjmedia_sdp_conn *conn;
636 pjmedia_sdp_session *answer;
637 pj_bool_t is_remote_active;
638 pj_status_t status;
639
640 inv_data = inv->dlg->mod_data[pjsua.mod.id];
641
642 /*
643 * See if remote is offering active media (i.e. not on-hold)
644 */
645 is_remote_active = PJ_TRUE;
646
647 conn = offer->media[0]->conn;
648 if (!conn)
649 conn = offer->conn;
650
651 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
652 pj_strcmp2(&conn->addr, "0")==0)
653 {
654 is_remote_active = PJ_FALSE;
655
656 }
657 else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))
658 {
659 is_remote_active = PJ_FALSE;
660 }
661
662 PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s",
663 (is_remote_active ? "active" : "inactive")));
664
665 /* Supply candidate answer */
666 if (is_remote_active) {
667 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1,
668 &pjsua.med_sock_info[inv_data->call_slot],
669 &answer);
670 } else {
671 status = create_inactive_sdp( inv_data, &answer );
672 }
673
674 if (status != PJ_SUCCESS) {
675 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
676 return;
677 }
678
679 status = pjsip_inv_set_sdp_answer(inv, answer);
680 if (status != PJ_SUCCESS) {
681 pjsua_perror(THIS_FILE, "Unable to set answer", status);
682 return;
683 }
684
685}
686
687
688/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000689 * Callback to be called when SDP offer/answer negotiation has just completed
690 * in the session. This function will start/update media if negotiation
691 * has succeeded.
692 */
693void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
694{
695 struct pjsua_inv_data *inv_data;
696 const pjmedia_sdp_session *local_sdp;
697 const pjmedia_sdp_session *remote_sdp;
Benny Prijono26ff9062006-02-21 23:47:00 +0000698 pjmedia_port *media_port;
699 pj_str_t port_name;
700 char tmp[PJSIP_MAX_URL_SIZE];
Benny Prijono84126ab2006-02-09 09:30:09 +0000701
702 if (status != PJ_SUCCESS) {
703
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000704 pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000705 return;
706
707 }
708
709 /* Destroy existing media session, if any. */
710
711 inv_data = inv->dlg->mod_data[pjsua.mod.id];
712 if (inv_data && inv_data->session) {
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000713 pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot);
Benny Prijono84126ab2006-02-09 09:30:09 +0000714 pjmedia_session_destroy(inv_data->session);
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000715 pjsua.med_sock_use[inv_data->call_slot] = 0;
Benny Prijono84126ab2006-02-09 09:30:09 +0000716 inv_data->session = NULL;
717 }
718
719 /* Get local and remote SDP */
720
721 status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
722 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000723 pjsua_perror(THIS_FILE,
724 "Unable to retrieve currently active local SDP",
725 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000726 return;
727 }
728
729
730 status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
731 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000732 pjsua_perror(THIS_FILE,
733 "Unable to retrieve currently active remote SDP",
734 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000735 return;
736 }
737
Benny Prijono84126ab2006-02-09 09:30:09 +0000738 /* Create new media session.
739 * The media session is active immediately.
740 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000741 if (pjsua.null_audio)
742 return;
743
744 status = pjmedia_session_create( pjsua.med_endpt, 1,
745 &pjsua.med_sock_info[inv_data->call_slot],
746 local_sdp, remote_sdp,
Benny Prijono06c70942006-02-22 12:06:39 +0000747 inv_data,
Benny Prijono26ff9062006-02-21 23:47:00 +0000748 &inv_data->session );
749 if (status != PJ_SUCCESS) {
750 pjsua_perror(THIS_FILE, "Unable to create media session",
751 status);
752 return;
Benny Prijono84126ab2006-02-09 09:30:09 +0000753 }
Benny Prijono26ff9062006-02-21 23:47:00 +0000754
755
756 /* Get the port interface of the first stream in the session.
757 * We need the port interface to add to the conference bridge.
758 */
759 pjmedia_session_get_port(inv_data->session, 0, &media_port);
760
761
762 /*
763 * Add the call to conference bridge.
764 */
765 port_name.ptr = tmp;
766 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
767 inv_data->inv->dlg->remote.info->uri,
768 tmp, sizeof(tmp));
769 if (port_name.slen < 1) {
770 port_name = pj_str("call");
771 }
772 status = pjmedia_conf_add_port( pjsua.mconf, inv->pool,
773 media_port,
774 &port_name,
775 &inv_data->conf_slot);
776 if (status != PJ_SUCCESS) {
777 pjsua_perror(THIS_FILE, "Unable to create conference slot",
778 status);
779 pjmedia_session_destroy(inv_data->session);
780 inv_data->session = NULL;
781 return;
782 }
783
Benny Prijono64f851e2006-02-23 13:49:28 +0000784 /* If auto-play is configured, connect the call to the file player
785 * port
Benny Prijono26ff9062006-02-21 23:47:00 +0000786 */
Benny Prijono64f851e2006-02-23 13:49:28 +0000787 if (pjsua.wav_file && inv->role == PJSIP_ROLE_UAS) {
788
789 pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,
790 inv_data->conf_slot);
791
792 } else {
793
794 /* Connect new call to the sound device port (port zero) in the
795 * main conference bridge.
796 */
797 pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot);
798 pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0);
799 }
800
Benny Prijono26ff9062006-02-21 23:47:00 +0000801
802 /* Done. */
803 {
804 struct pjmedia_session_info sess_info;
805 char info[80];
806 int info_len = 0;
807 unsigned i;
808
809 pjmedia_session_get_info(inv_data->session, &sess_info);
810 for (i=0; i<sess_info.stream_cnt; ++i) {
811 int len;
812 const char *dir;
813 pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
814
815 switch (strm_info->dir) {
816 case PJMEDIA_DIR_NONE:
817 dir = "inactive";
818 break;
819 case PJMEDIA_DIR_ENCODING:
820 dir = "sendonly";
821 break;
822 case PJMEDIA_DIR_DECODING:
823 dir = "recvonly";
824 break;
825 case PJMEDIA_DIR_ENCODING_DECODING:
826 dir = "sendrecv";
827 break;
828 default:
829 dir = "unknown";
830 break;
831 }
832 len = pj_ansi_sprintf( info+info_len,
833 ", stream #%d: %.*s (%s)", i,
834 (int)strm_info->fmt.encoding_name.slen,
835 (int)strm_info->fmt.encoding_name.ptr,
836 dir);
837 if (len > 0)
838 info_len += len;
839 }
840 PJ_LOG(3,(THIS_FILE,"Media started%s", info));
841 }
842}
843
844
845/*
846 * Hangup call.
847 */
848void pjsua_inv_hangup(struct pjsua_inv_data *inv_session, int code)
849{
850 pj_status_t status;
851 pjsip_tx_data *tdata;
852
853 status = pjsip_inv_end_session(inv_session->inv,
854 code, NULL, &tdata);
855 if (status != PJ_SUCCESS) {
856 pjsua_perror(THIS_FILE,
857 "Failed to create end session message",
858 status);
859 return;
860 }
861
Benny Prijonofccab712006-02-22 22:23:22 +0000862 /* pjsip_inv_end_session may return PJ_SUCCESS with NULL
863 * as p_tdata when INVITE transaction has not been answered
864 * with any provisional responses.
865 */
866 if (tdata == NULL)
867 return;
868
Benny Prijono26ff9062006-02-21 23:47:00 +0000869 status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL);
870 if (status != PJ_SUCCESS) {
871 pjsua_perror(THIS_FILE,
872 "Failed to send end session message",
873 status);
874 return;
875 }
876}
877
878
879/*
880 * Put call on-Hold.
881 */
882void pjsua_inv_set_hold(struct pjsua_inv_data *inv_session)
883{
884 pjmedia_sdp_session *sdp;
885 pjsip_inv_session *inv = inv_session->inv;
886 pjsip_tx_data *tdata;
887 pj_status_t status;
888
889 if (inv->state != PJSIP_INV_STATE_CONFIRMED) {
890 PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
891 return;
892 }
893
894 status = create_inactive_sdp(inv_session, &sdp);
895 if (status != PJ_SUCCESS)
896 return;
897
898 /* Send re-INVITE with new offer */
899 status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata);
900 if (status != PJ_SUCCESS) {
901 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
902 return;
903 }
904
905 status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL);
906 if (status != PJ_SUCCESS) {
907 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
908 return;
909 }
910}
911
912
913/*
914 * re-INVITE.
915 */
916void pjsua_inv_reinvite(struct pjsua_inv_data *inv_session)
917{
918 pjmedia_sdp_session *sdp;
919 pjsip_tx_data *tdata;
920 pjsip_inv_session *inv = inv_session->inv;
921 pj_status_t status;
922
923
924 if (inv->state != PJSIP_INV_STATE_CONFIRMED) {
925 PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
926 return;
927 }
928
929 /* Create SDP */
930 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1,
931 &pjsua.med_sock_info[inv_session->call_slot],
932 &sdp);
933 if (status != PJ_SUCCESS) {
934 pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", status);
935 return;
936 }
937
938 /* Send re-INVITE with new offer */
939 status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata);
940 if (status != PJ_SUCCESS) {
941 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
942 return;
943 }
944
945 status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL);
946 if (status != PJ_SUCCESS) {
947 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
948 return;
949 }
950}
951
952
953/*
954 * Transfer call.
955 */
956void pjsua_inv_xfer_call(struct pjsua_inv_data *inv_session,
957 const char *dest)
958{
959 pjsip_evsub *sub;
960 pjsip_tx_data *tdata;
961 pj_str_t tmp;
962 pj_status_t status;
963
964
965 /* Create xfer client subscription.
966 * We're not interested in knowing the transfer result, so we
967 * put NULL as the callback.
968 */
969 status = pjsip_xfer_create_uac(inv_session->inv->dlg, NULL, &sub);
970 if (status != PJ_SUCCESS) {
971 pjsua_perror(THIS_FILE, "Unable to create xfer", status);
972 return;
973 }
974
975 /*
976 * Create REFER request.
977 */
978 status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
979 if (status != PJ_SUCCESS) {
980 pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
981 return;
982 }
983
984 /* Send. */
985 status = pjsip_xfer_send_request(sub, tdata);
986 if (status != PJ_SUCCESS) {
987 pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
988 return;
989 }
990
991 /* For simplicity (that's what this program is intended to be!),
992 * leave the original invite session as it is. More advanced application
993 * may want to hold the INVITE, or terminate the invite, or whatever.
994 */
Benny Prijono84126ab2006-02-09 09:30:09 +0000995}
Benny Prijono834aee32006-02-19 01:38:06 +0000996
997
998/*
999 * Terminate all calls.
1000 */
1001void pjsua_inv_shutdown()
1002{
1003 struct pjsua_inv_data *inv_data, *next;
1004
1005 inv_data = pjsua.inv_list.next;
1006 while (inv_data != &pjsua.inv_list) {
1007 pjsip_tx_data *tdata;
1008
1009 next = inv_data->next;
1010
Benny Prijonofccab712006-02-22 22:23:22 +00001011 if (pjsip_inv_end_session(inv_data->inv, 410, NULL, &tdata)==0) {
1012 if (tdata)
1013 pjsip_inv_send_msg(inv_data->inv, tdata, NULL);
1014 }
Benny Prijono834aee32006-02-19 01:38:06 +00001015
1016 inv_data = next;
1017 }
1018}
1019
Benny Prijono26ff9062006-02-21 23:47:00 +00001020