blob: 824943cdd0df6fe7e4043cd1e6ed5cdc12155424 [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
281 /* Answer with 100 (using the dialog, not invite): */
282
283 status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response);
284 if (status != PJ_SUCCESS) {
285
286 pjsip_dlg_respond(dlg, rdata, 500, NULL);
287
288 /* Free call socket. */
289 pjsua.med_sock_use[med_sk_index] = 0;
290
291 // TODO: Need to delete dialog
292
293 } else {
294 status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata),
295 response);
296 }
297
298 /* This INVITE request has been handled. */
299 return PJ_TRUE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000300}
301
302
303/*
304 * This callback receives notification from invite session when the
305 * session state has changed.
306 */
307void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
308{
Benny Prijono26ff9062006-02-21 23:47:00 +0000309 struct pjsua_inv_data *inv_data;
310
311 inv_data = inv->dlg->mod_data[pjsua.mod.id];
312
313 /* If this is an outgoing INVITE that was created because of
314 * REFER/transfer, send NOTIFY to transferer.
315 */
316 if (inv_data && inv_data->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE)
317 {
318 int st_code = -1;
319 pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
320
321
322 switch (inv->state) {
323 case PJSIP_INV_STATE_NULL:
324 case PJSIP_INV_STATE_CALLING:
325 /* Do nothing */
326 break;
327
328 case PJSIP_INV_STATE_EARLY:
329 case PJSIP_INV_STATE_CONNECTING:
330 st_code = e->body.tsx_state.tsx->status_code;
331 ev_state = PJSIP_EVSUB_STATE_ACTIVE;
332 break;
333
334 case PJSIP_INV_STATE_CONFIRMED:
335 /* When state is confirmed, send the final 200/OK and terminate
336 * subscription.
337 */
338 st_code = e->body.tsx_state.tsx->status_code;
339 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
340 break;
341
342 case PJSIP_INV_STATE_DISCONNECTED:
343 st_code = e->body.tsx_state.tsx->status_code;
344 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
345 break;
346 }
347
348 if (st_code != -1) {
349 pjsip_tx_data *tdata;
350 pj_status_t status;
351
352 status = pjsip_xfer_notify( inv_data->xfer_sub,
353 ev_state, st_code,
354 NULL, &tdata);
355 if (status != PJ_SUCCESS) {
356 pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);
357 } else {
358 status = pjsip_xfer_send_request(inv_data->xfer_sub, tdata);
359 if (status != PJ_SUCCESS) {
360 pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);
361 }
362 }
363 }
364 }
365
Benny Prijono84126ab2006-02-09 09:30:09 +0000366
367 /* Destroy media session when invite session is disconnected. */
368 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono632ce712006-02-09 14:01:40 +0000369
370 pj_assert(inv_data != NULL);
371
Benny Prijono84126ab2006-02-09 09:30:09 +0000372 if (inv_data && inv_data->session) {
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000373 pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot);
Benny Prijono84126ab2006-02-09 09:30:09 +0000374 pjmedia_session_destroy(inv_data->session);
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000375 pjsua.med_sock_use[inv_data->call_slot] = 0;
Benny Prijono84126ab2006-02-09 09:30:09 +0000376 inv_data->session = NULL;
377
378 PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
379 }
380
Benny Prijono632ce712006-02-09 14:01:40 +0000381 if (inv_data) {
382
383 pj_list_erase(inv_data);
384
385 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000386 }
387
388 pjsua_ui_inv_on_state_changed(inv, e);
389}
390
391
392/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000393 * Callback called by event framework when the xfer subscription state
394 * has changed.
395 */
396static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
397{
398
399 PJ_UNUSED_ARG(event);
400
401 /*
402 * We're only interested when subscription is terminated, to
403 * clear the xfer_sub member of the inv_data.
404 */
405 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
406 struct pjsua_inv_data *inv_data;
407
408 inv_data = pjsip_evsub_get_mod_data(sub, pjsua.mod.id);
409 if (!inv_data)
410 return;
411
412 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL);
413 inv_data->xfer_sub = NULL;
414
415 PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated"));
416 }
417}
418
419
420/*
421 * Follow transfer (REFER) request.
422 */
423static void on_call_transfered( pjsip_inv_session *inv,
424 pjsip_rx_data *rdata )
425{
426 pj_status_t status;
427 pjsip_tx_data *tdata;
428 struct pjsua_inv_data *inv_data;
429 const pj_str_t str_refer_to = { "Refer-To", 8};
430 pjsip_generic_string_hdr *refer_to;
431 char *uri;
432 struct pjsip_evsub_user xfer_cb;
433 pjsip_evsub *sub;
434
435 /* Find the Refer-To header */
436 refer_to = (pjsip_generic_string_hdr*)
437 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
438
439 if (refer_to == NULL) {
440 /* Invalid Request.
441 * No Refer-To header!
442 */
443 PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!"));
444 pjsip_dlg_respond( inv->dlg, rdata, 400, NULL);
445 return;
446 }
447
448 PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s",
449 (int)inv->dlg->remote.info_str.slen,
450 inv->dlg->remote.info_str.ptr,
451 (int)refer_to->hvalue.slen,
452 refer_to->hvalue.ptr));
453
454 /* Init callback */
455 pj_memset(&xfer_cb, 0, sizeof(xfer_cb));
456 xfer_cb.on_evsub_state = &xfer_on_evsub_state;
457
458 /* Create transferee event subscription */
459 status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
460 if (status != PJ_SUCCESS) {
461 pjsua_perror(THIS_FILE, "Unable to create xfer uas", status);
462 pjsip_dlg_respond( inv->dlg, rdata, 500, NULL);
463 return;
464 }
465
466 /* Accept the REFER request, send 200 (OK). */
467 pjsip_xfer_accept(sub, rdata, 200, NULL);
468
469 /* Create initial NOTIFY request */
470 status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
471 100, NULL, &tdata);
472 if (status != PJ_SUCCESS) {
473 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status);
474 return;
475 }
476
477 /* Send initial NOTIFY request */
478 status = pjsip_xfer_send_request( sub, tdata);
479 if (status != PJ_SUCCESS) {
480 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status);
481 return;
482 }
483
484 /* We're cheating here.
485 * We need to get a null terminated string from a pj_str_t.
486 * So grab the pointer from the hvalue and NULL terminate it, knowing
487 * that the NULL position will be occupied by a newline.
488 */
489 uri = refer_to->hvalue.ptr;
490 uri[refer_to->hvalue.slen] = '\0';
491
492 /* Now make the outgoing call. */
493 status = pjsua_invite(uri, &inv_data);
494 if (status != PJ_SUCCESS) {
495
496 /* Notify xferer about the error */
497 status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
498 500, NULL, &tdata);
499 if (status != PJ_SUCCESS) {
500 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",
501 status);
502 return;
503 }
504 status = pjsip_xfer_send_request(sub, tdata);
505 if (status != PJ_SUCCESS) {
506 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",
507 status);
508 return;
509 }
510 return;
511 }
512
513 /* Put the server subscription in inv_data.
514 * Subsequent state changed in pjsua_inv_on_state_changed() will be
515 * reported back to the server subscription.
516 */
517 inv_data->xfer_sub = sub;
518
519 /* Put the invite_data in the subscription. */
520 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, inv_data);
521}
522
523
524/*
525 * This callback is called when transaction state has changed in INVITE
526 * session. We use this to trap incoming REFER request.
527 */
528void pjsua_inv_on_tsx_state_changed(pjsip_inv_session *inv,
529 pjsip_transaction *tsx,
530 pjsip_event *e)
531{
532 if (tsx->role==PJSIP_ROLE_UAS &&
533 tsx->state==PJSIP_TSX_STATE_TRYING &&
534 pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0)
535 {
536 /*
537 * Incoming REFER request.
538 */
539 on_call_transfered(inv, e->body.tsx_state.src.rdata);
540 }
541}
542
543
544/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000545 * This callback is called by invite session framework when UAC session
546 * has forked.
547 */
548void pjsua_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e)
549{
550 PJ_UNUSED_ARG(inv);
551 PJ_UNUSED_ARG(e);
552
553 PJ_TODO(HANDLE_FORKED_DIALOG);
554}
555
556
557/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000558 * Create inactive SDP for call hold.
559 */
560static pj_status_t create_inactive_sdp(struct pjsua_inv_data *inv_session,
561 pjmedia_sdp_session **p_answer)
562{
563 pj_status_t status;
564 pjmedia_sdp_conn *conn;
565 pjmedia_sdp_attr *attr;
566 pjmedia_sdp_session *sdp;
567
568 /* Create new offer */
569 status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1,
570 &pjsua.med_sock_info[inv_session->call_slot],
571 &sdp);
572 if (status != PJ_SUCCESS) {
573 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
574 return status;
575 }
576
577 /* Get SDP media connection line */
578 conn = sdp->media[0]->conn;
579 if (!conn)
580 conn = sdp->conn;
581
582 /* Modify address */
583 conn->addr = pj_str("0.0.0.0");
584
585 /* Remove existing directions attributes */
586 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
587 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
588 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
589 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
590
591 /* Add inactive attribute */
592 attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL);
593 pjmedia_sdp_media_add_attr(sdp->media[0], attr);
594
595 *p_answer = sdp;
596
597 return status;
598}
599
600/*
601 * Called when session received new offer.
602 */
603void pjsua_inv_on_rx_offer( pjsip_inv_session *inv,
604 const pjmedia_sdp_session *offer)
605{
606 struct pjsua_inv_data *inv_data;
607 pjmedia_sdp_conn *conn;
608 pjmedia_sdp_session *answer;
609 pj_bool_t is_remote_active;
610 pj_status_t status;
611
612 inv_data = inv->dlg->mod_data[pjsua.mod.id];
613
614 /*
615 * See if remote is offering active media (i.e. not on-hold)
616 */
617 is_remote_active = PJ_TRUE;
618
619 conn = offer->media[0]->conn;
620 if (!conn)
621 conn = offer->conn;
622
623 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
624 pj_strcmp2(&conn->addr, "0")==0)
625 {
626 is_remote_active = PJ_FALSE;
627
628 }
629 else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))
630 {
631 is_remote_active = PJ_FALSE;
632 }
633
634 PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s",
635 (is_remote_active ? "active" : "inactive")));
636
637 /* Supply candidate answer */
638 if (is_remote_active) {
639 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1,
640 &pjsua.med_sock_info[inv_data->call_slot],
641 &answer);
642 } else {
643 status = create_inactive_sdp( inv_data, &answer );
644 }
645
646 if (status != PJ_SUCCESS) {
647 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
648 return;
649 }
650
651 status = pjsip_inv_set_sdp_answer(inv, answer);
652 if (status != PJ_SUCCESS) {
653 pjsua_perror(THIS_FILE, "Unable to set answer", status);
654 return;
655 }
656
657}
658
659
660/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000661 * Callback to be called when SDP offer/answer negotiation has just completed
662 * in the session. This function will start/update media if negotiation
663 * has succeeded.
664 */
665void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
666{
667 struct pjsua_inv_data *inv_data;
668 const pjmedia_sdp_session *local_sdp;
669 const pjmedia_sdp_session *remote_sdp;
Benny Prijono26ff9062006-02-21 23:47:00 +0000670 pjmedia_port *media_port;
671 pj_str_t port_name;
672 char tmp[PJSIP_MAX_URL_SIZE];
Benny Prijono84126ab2006-02-09 09:30:09 +0000673
674 if (status != PJ_SUCCESS) {
675
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000676 pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000677 return;
678
679 }
680
681 /* Destroy existing media session, if any. */
682
683 inv_data = inv->dlg->mod_data[pjsua.mod.id];
684 if (inv_data && inv_data->session) {
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000685 pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot);
Benny Prijono84126ab2006-02-09 09:30:09 +0000686 pjmedia_session_destroy(inv_data->session);
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000687 pjsua.med_sock_use[inv_data->call_slot] = 0;
Benny Prijono84126ab2006-02-09 09:30:09 +0000688 inv_data->session = NULL;
689 }
690
691 /* Get local and remote SDP */
692
693 status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
694 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000695 pjsua_perror(THIS_FILE,
696 "Unable to retrieve currently active local SDP",
697 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000698 return;
699 }
700
701
702 status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
703 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000704 pjsua_perror(THIS_FILE,
705 "Unable to retrieve currently active remote SDP",
706 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000707 return;
708 }
709
Benny Prijono84126ab2006-02-09 09:30:09 +0000710 /* Create new media session.
711 * The media session is active immediately.
712 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000713 if (pjsua.null_audio)
714 return;
715
716 status = pjmedia_session_create( pjsua.med_endpt, 1,
717 &pjsua.med_sock_info[inv_data->call_slot],
718 local_sdp, remote_sdp,
Benny Prijono06c70942006-02-22 12:06:39 +0000719 inv_data,
Benny Prijono26ff9062006-02-21 23:47:00 +0000720 &inv_data->session );
721 if (status != PJ_SUCCESS) {
722 pjsua_perror(THIS_FILE, "Unable to create media session",
723 status);
724 return;
Benny Prijono84126ab2006-02-09 09:30:09 +0000725 }
Benny Prijono26ff9062006-02-21 23:47:00 +0000726
727
728 /* Get the port interface of the first stream in the session.
729 * We need the port interface to add to the conference bridge.
730 */
731 pjmedia_session_get_port(inv_data->session, 0, &media_port);
732
733
734 /*
735 * Add the call to conference bridge.
736 */
737 port_name.ptr = tmp;
738 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
739 inv_data->inv->dlg->remote.info->uri,
740 tmp, sizeof(tmp));
741 if (port_name.slen < 1) {
742 port_name = pj_str("call");
743 }
744 status = pjmedia_conf_add_port( pjsua.mconf, inv->pool,
745 media_port,
746 &port_name,
747 &inv_data->conf_slot);
748 if (status != PJ_SUCCESS) {
749 pjsua_perror(THIS_FILE, "Unable to create conference slot",
750 status);
751 pjmedia_session_destroy(inv_data->session);
752 inv_data->session = NULL;
753 return;
754 }
755
756 /* Connect new call to the sound device port (port zero) in the
757 * main conference bridge.
758 */
759 pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot);
760 pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0);
761
762 /* Done. */
763 {
764 struct pjmedia_session_info sess_info;
765 char info[80];
766 int info_len = 0;
767 unsigned i;
768
769 pjmedia_session_get_info(inv_data->session, &sess_info);
770 for (i=0; i<sess_info.stream_cnt; ++i) {
771 int len;
772 const char *dir;
773 pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
774
775 switch (strm_info->dir) {
776 case PJMEDIA_DIR_NONE:
777 dir = "inactive";
778 break;
779 case PJMEDIA_DIR_ENCODING:
780 dir = "sendonly";
781 break;
782 case PJMEDIA_DIR_DECODING:
783 dir = "recvonly";
784 break;
785 case PJMEDIA_DIR_ENCODING_DECODING:
786 dir = "sendrecv";
787 break;
788 default:
789 dir = "unknown";
790 break;
791 }
792 len = pj_ansi_sprintf( info+info_len,
793 ", stream #%d: %.*s (%s)", i,
794 (int)strm_info->fmt.encoding_name.slen,
795 (int)strm_info->fmt.encoding_name.ptr,
796 dir);
797 if (len > 0)
798 info_len += len;
799 }
800 PJ_LOG(3,(THIS_FILE,"Media started%s", info));
801 }
802}
803
804
805/*
806 * Hangup call.
807 */
808void pjsua_inv_hangup(struct pjsua_inv_data *inv_session, int code)
809{
810 pj_status_t status;
811 pjsip_tx_data *tdata;
812
813 status = pjsip_inv_end_session(inv_session->inv,
814 code, NULL, &tdata);
815 if (status != PJ_SUCCESS) {
816 pjsua_perror(THIS_FILE,
817 "Failed to create end session message",
818 status);
819 return;
820 }
821
822 status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL);
823 if (status != PJ_SUCCESS) {
824 pjsua_perror(THIS_FILE,
825 "Failed to send end session message",
826 status);
827 return;
828 }
829}
830
831
832/*
833 * Put call on-Hold.
834 */
835void pjsua_inv_set_hold(struct pjsua_inv_data *inv_session)
836{
837 pjmedia_sdp_session *sdp;
838 pjsip_inv_session *inv = inv_session->inv;
839 pjsip_tx_data *tdata;
840 pj_status_t status;
841
842 if (inv->state != PJSIP_INV_STATE_CONFIRMED) {
843 PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
844 return;
845 }
846
847 status = create_inactive_sdp(inv_session, &sdp);
848 if (status != PJ_SUCCESS)
849 return;
850
851 /* Send re-INVITE with new offer */
852 status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata);
853 if (status != PJ_SUCCESS) {
854 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
855 return;
856 }
857
858 status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL);
859 if (status != PJ_SUCCESS) {
860 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
861 return;
862 }
863}
864
865
866/*
867 * re-INVITE.
868 */
869void pjsua_inv_reinvite(struct pjsua_inv_data *inv_session)
870{
871 pjmedia_sdp_session *sdp;
872 pjsip_tx_data *tdata;
873 pjsip_inv_session *inv = inv_session->inv;
874 pj_status_t status;
875
876
877 if (inv->state != PJSIP_INV_STATE_CONFIRMED) {
878 PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
879 return;
880 }
881
882 /* Create SDP */
883 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1,
884 &pjsua.med_sock_info[inv_session->call_slot],
885 &sdp);
886 if (status != PJ_SUCCESS) {
887 pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", status);
888 return;
889 }
890
891 /* Send re-INVITE with new offer */
892 status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata);
893 if (status != PJ_SUCCESS) {
894 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
895 return;
896 }
897
898 status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL);
899 if (status != PJ_SUCCESS) {
900 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
901 return;
902 }
903}
904
905
906/*
907 * Transfer call.
908 */
909void pjsua_inv_xfer_call(struct pjsua_inv_data *inv_session,
910 const char *dest)
911{
912 pjsip_evsub *sub;
913 pjsip_tx_data *tdata;
914 pj_str_t tmp;
915 pj_status_t status;
916
917
918 /* Create xfer client subscription.
919 * We're not interested in knowing the transfer result, so we
920 * put NULL as the callback.
921 */
922 status = pjsip_xfer_create_uac(inv_session->inv->dlg, NULL, &sub);
923 if (status != PJ_SUCCESS) {
924 pjsua_perror(THIS_FILE, "Unable to create xfer", status);
925 return;
926 }
927
928 /*
929 * Create REFER request.
930 */
931 status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
932 if (status != PJ_SUCCESS) {
933 pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
934 return;
935 }
936
937 /* Send. */
938 status = pjsip_xfer_send_request(sub, tdata);
939 if (status != PJ_SUCCESS) {
940 pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
941 return;
942 }
943
944 /* For simplicity (that's what this program is intended to be!),
945 * leave the original invite session as it is. More advanced application
946 * may want to hold the INVITE, or terminate the invite, or whatever.
947 */
Benny Prijono84126ab2006-02-09 09:30:09 +0000948}
Benny Prijono834aee32006-02-19 01:38:06 +0000949
950
951/*
952 * Terminate all calls.
953 */
954void pjsua_inv_shutdown()
955{
956 struct pjsua_inv_data *inv_data, *next;
957
958 inv_data = pjsua.inv_list.next;
959 while (inv_data != &pjsua.inv_list) {
960 pjsip_tx_data *tdata;
961
962 next = inv_data->next;
963
964 if (pjsip_inv_end_session(inv_data->inv, 410, NULL, &tdata)==0)
965 pjsip_inv_send_msg(inv_data->inv, tdata, NULL);
966
967 inv_data = next;
968 }
969}
970
Benny Prijono26ff9062006-02-21 23:47:00 +0000971