blob: 34bf651f17eec5dd42c810978068e06dd64d3ceb [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,
719 &inv_data->session );
720 if (status != PJ_SUCCESS) {
721 pjsua_perror(THIS_FILE, "Unable to create media session",
722 status);
723 return;
Benny Prijono84126ab2006-02-09 09:30:09 +0000724 }
Benny Prijono26ff9062006-02-21 23:47:00 +0000725
726
727 /* Get the port interface of the first stream in the session.
728 * We need the port interface to add to the conference bridge.
729 */
730 pjmedia_session_get_port(inv_data->session, 0, &media_port);
731
732
733 /*
734 * Add the call to conference bridge.
735 */
736 port_name.ptr = tmp;
737 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
738 inv_data->inv->dlg->remote.info->uri,
739 tmp, sizeof(tmp));
740 if (port_name.slen < 1) {
741 port_name = pj_str("call");
742 }
743 status = pjmedia_conf_add_port( pjsua.mconf, inv->pool,
744 media_port,
745 &port_name,
746 &inv_data->conf_slot);
747 if (status != PJ_SUCCESS) {
748 pjsua_perror(THIS_FILE, "Unable to create conference slot",
749 status);
750 pjmedia_session_destroy(inv_data->session);
751 inv_data->session = NULL;
752 return;
753 }
754
755 /* Connect new call to the sound device port (port zero) in the
756 * main conference bridge.
757 */
758 pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot);
759 pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0);
760
761 /* Done. */
762 {
763 struct pjmedia_session_info sess_info;
764 char info[80];
765 int info_len = 0;
766 unsigned i;
767
768 pjmedia_session_get_info(inv_data->session, &sess_info);
769 for (i=0; i<sess_info.stream_cnt; ++i) {
770 int len;
771 const char *dir;
772 pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
773
774 switch (strm_info->dir) {
775 case PJMEDIA_DIR_NONE:
776 dir = "inactive";
777 break;
778 case PJMEDIA_DIR_ENCODING:
779 dir = "sendonly";
780 break;
781 case PJMEDIA_DIR_DECODING:
782 dir = "recvonly";
783 break;
784 case PJMEDIA_DIR_ENCODING_DECODING:
785 dir = "sendrecv";
786 break;
787 default:
788 dir = "unknown";
789 break;
790 }
791 len = pj_ansi_sprintf( info+info_len,
792 ", stream #%d: %.*s (%s)", i,
793 (int)strm_info->fmt.encoding_name.slen,
794 (int)strm_info->fmt.encoding_name.ptr,
795 dir);
796 if (len > 0)
797 info_len += len;
798 }
799 PJ_LOG(3,(THIS_FILE,"Media started%s", info));
800 }
801}
802
803
804/*
805 * Hangup call.
806 */
807void pjsua_inv_hangup(struct pjsua_inv_data *inv_session, int code)
808{
809 pj_status_t status;
810 pjsip_tx_data *tdata;
811
812 status = pjsip_inv_end_session(inv_session->inv,
813 code, NULL, &tdata);
814 if (status != PJ_SUCCESS) {
815 pjsua_perror(THIS_FILE,
816 "Failed to create end session message",
817 status);
818 return;
819 }
820
821 status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL);
822 if (status != PJ_SUCCESS) {
823 pjsua_perror(THIS_FILE,
824 "Failed to send end session message",
825 status);
826 return;
827 }
828}
829
830
831/*
832 * Put call on-Hold.
833 */
834void pjsua_inv_set_hold(struct pjsua_inv_data *inv_session)
835{
836 pjmedia_sdp_session *sdp;
837 pjsip_inv_session *inv = inv_session->inv;
838 pjsip_tx_data *tdata;
839 pj_status_t status;
840
841 if (inv->state != PJSIP_INV_STATE_CONFIRMED) {
842 PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
843 return;
844 }
845
846 status = create_inactive_sdp(inv_session, &sdp);
847 if (status != PJ_SUCCESS)
848 return;
849
850 /* Send re-INVITE with new offer */
851 status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata);
852 if (status != PJ_SUCCESS) {
853 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
854 return;
855 }
856
857 status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL);
858 if (status != PJ_SUCCESS) {
859 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
860 return;
861 }
862}
863
864
865/*
866 * re-INVITE.
867 */
868void pjsua_inv_reinvite(struct pjsua_inv_data *inv_session)
869{
870 pjmedia_sdp_session *sdp;
871 pjsip_tx_data *tdata;
872 pjsip_inv_session *inv = inv_session->inv;
873 pj_status_t status;
874
875
876 if (inv->state != PJSIP_INV_STATE_CONFIRMED) {
877 PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
878 return;
879 }
880
881 /* Create SDP */
882 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1,
883 &pjsua.med_sock_info[inv_session->call_slot],
884 &sdp);
885 if (status != PJ_SUCCESS) {
886 pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", status);
887 return;
888 }
889
890 /* Send re-INVITE with new offer */
891 status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata);
892 if (status != PJ_SUCCESS) {
893 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
894 return;
895 }
896
897 status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL);
898 if (status != PJ_SUCCESS) {
899 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
900 return;
901 }
902}
903
904
905/*
906 * Transfer call.
907 */
908void pjsua_inv_xfer_call(struct pjsua_inv_data *inv_session,
909 const char *dest)
910{
911 pjsip_evsub *sub;
912 pjsip_tx_data *tdata;
913 pj_str_t tmp;
914 pj_status_t status;
915
916
917 /* Create xfer client subscription.
918 * We're not interested in knowing the transfer result, so we
919 * put NULL as the callback.
920 */
921 status = pjsip_xfer_create_uac(inv_session->inv->dlg, NULL, &sub);
922 if (status != PJ_SUCCESS) {
923 pjsua_perror(THIS_FILE, "Unable to create xfer", status);
924 return;
925 }
926
927 /*
928 * Create REFER request.
929 */
930 status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
931 if (status != PJ_SUCCESS) {
932 pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
933 return;
934 }
935
936 /* Send. */
937 status = pjsip_xfer_send_request(sub, tdata);
938 if (status != PJ_SUCCESS) {
939 pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
940 return;
941 }
942
943 /* For simplicity (that's what this program is intended to be!),
944 * leave the original invite session as it is. More advanced application
945 * may want to hold the INVITE, or terminate the invite, or whatever.
946 */
Benny Prijono84126ab2006-02-09 09:30:09 +0000947}
Benny Prijono834aee32006-02-19 01:38:06 +0000948
949
950/*
951 * Terminate all calls.
952 */
953void pjsua_inv_shutdown()
954{
955 struct pjsua_inv_data *inv_data, *next;
956
957 inv_data = pjsua.inv_list.next;
958 while (inv_data != &pjsua.inv_list) {
959 pjsip_tx_data *tdata;
960
961 next = inv_data->next;
962
963 if (pjsip_inv_end_session(inv_data->inv, 410, NULL, &tdata)==0)
964 pjsip_inv_send_msg(inv_data->inv, tdata, NULL);
965
966 inv_data = next;
967 }
968}
969
Benny Prijono26ff9062006-02-21 23:47:00 +0000970