blob: b245a4917d229fb796fc20605df586fb68bf3ff5 [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 */
Benny Prijono4f9f64e2006-02-27 00:00:30 +000019#include <pjsua-lib/pjsua.h>
Benny Prijono84126ab2006-02-09 09:30:09 +000020#include <pj/log.h>
21
22
23/*
Benny Prijonob0808372006-03-02 21:18:58 +000024 * pjsua_call.c
Benny Prijono84126ab2006-02-09 09:30:09 +000025 *
Benny Prijonob0808372006-03-02 21:18:58 +000026 * Call (INVITE) related stuffs.
Benny Prijono84126ab2006-02-09 09:30:09 +000027 */
28
29#define THIS_FILE "pjsua_inv.c"
30
31
32/**
33 * Make outgoing call.
34 */
Benny Prijonoa91a0032006-02-26 21:23:45 +000035pj_status_t pjsua_make_call(int acc_index,
36 const char *cstr_dest_uri,
37 int *p_call_index)
Benny Prijono84126ab2006-02-09 09:30:09 +000038{
39 pj_str_t dest_uri;
Benny Prijono1c2bf462006-03-05 11:54:02 +000040 pjsip_dialog *dlg = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +000041 pjmedia_sdp_session *offer;
Benny Prijono1c2bf462006-03-05 11:54:02 +000042 pjsip_inv_session *inv = NULL;
Benny Prijonoa91a0032006-02-26 21:23:45 +000043 int call_index = -1;
Benny Prijono84126ab2006-02-09 09:30:09 +000044 pjsip_tx_data *tdata;
45 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 Prijonoa91a0032006-02-26 21:23:45 +000051 /* Find free call slot. */
52 for (call_index=0; call_index<pjsua.max_calls; ++call_index) {
53 if (pjsua.calls[call_index].inv == NULL)
Benny Prijonof04ffdd2006-02-21 00:11:18 +000054 break;
55 }
56
Benny Prijonoa91a0032006-02-26 21:23:45 +000057 if (call_index == pjsua.max_calls) {
Benny Prijonof04ffdd2006-02-21 00:11:18 +000058 PJ_LOG(3,(THIS_FILE, "Error: too many calls!"));
59 return PJ_ETOOMANY;
60 }
61
Benny Prijono84126ab2006-02-09 09:30:09 +000062 /* Create outgoing dialog: */
63
Benny Prijonoa91a0032006-02-26 21:23:45 +000064 status = pjsip_dlg_create_uac( pjsip_ua_instance(),
65 &pjsua.acc[acc_index].local_uri,
66 &pjsua.acc[acc_index].contact_uri,
67 &dest_uri, &dest_uri,
Benny Prijono84126ab2006-02-09 09:30:09 +000068 &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
Benny Prijonoa91a0032006-02-26 21:23:45 +000076 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 1,
77 &pjsua.calls[call_index].skinfo,
Benny Prijonof04ffdd2006-02-21 00:11:18 +000078 &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
Benny Prijonoa91a0032006-02-26 21:23:45 +000095 pjsua.calls[call_index].inv = inv;
96
97 dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
98 inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
Benny Prijono84126ab2006-02-09 09:30:09 +000099
100
101 /* Set dialog Route-Set: */
102
Benny Prijonoa91a0032006-02-26 21:23:45 +0000103 if (!pj_list_empty(&pjsua.acc[acc_index].route_set))
104 pjsip_dlg_set_route_set(dlg, &pjsua.acc[acc_index].route_set);
Benny Prijono84126ab2006-02-09 09:30:09 +0000105
106
107 /* Set credentials: */
108
109 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,
110 pjsua.cred_info);
111
112
113 /* Create initial INVITE: */
114
115 status = pjsip_inv_invite(inv, &tdata);
116 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000117 pjsua_perror(THIS_FILE, "Unable to create initial INVITE request",
118 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000119 goto on_error;
120 }
121
122
123 /* Send initial INVITE: */
124
125 status = pjsip_inv_send_msg(inv, tdata, NULL);
126 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000127 pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",
128 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000129 goto on_error;
130 }
131
132
133 /* Done. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000134
135 ++pjsua.call_cnt;
136
137 if (p_call_index)
138 *p_call_index = call_index;
Benny Prijono84126ab2006-02-09 09:30:09 +0000139
140 return PJ_SUCCESS;
141
142
143on_error:
Benny Prijono1c2bf462006-03-05 11:54:02 +0000144 if (inv != NULL) {
145 pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE);
146 } else {
147 pjsip_dlg_terminate(dlg);
148 }
149
Benny Prijonoa91a0032006-02-26 21:23:45 +0000150 if (call_index != -1) {
151 pjsua.calls[call_index].inv = NULL;
152 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000153 return status;
154}
155
156
157/**
158 * Handle incoming INVITE request.
159 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000160pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
Benny Prijono84126ab2006-02-09 09:30:09 +0000161{
162 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
163 pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
164 pjsip_msg *msg = rdata->msg_info.msg;
Benny Prijono26ff9062006-02-21 23:47:00 +0000165 pjsip_tx_data *response = NULL;
166 unsigned options = 0;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000167 pjsip_inv_session *inv = NULL;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000168 int acc_index;
169 int call_index = -1;
Benny Prijono26ff9062006-02-21 23:47:00 +0000170 pjmedia_sdp_session *answer;
Benny Prijono26ff9062006-02-21 23:47:00 +0000171 pj_status_t status;
Benny Prijono84126ab2006-02-09 09:30:09 +0000172
Benny Prijono26ff9062006-02-21 23:47:00 +0000173 /* Don't want to handle anything but INVITE */
174 if (msg->line.req.method.id != PJSIP_INVITE_METHOD)
175 return PJ_FALSE;
176
177 /* Don't want to handle anything that's already associated with
178 * existing dialog or transaction.
Benny Prijono84126ab2006-02-09 09:30:09 +0000179 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000180 if (dlg || tsx)
181 return PJ_FALSE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000182
Benny Prijono84126ab2006-02-09 09:30:09 +0000183
Benny Prijono26ff9062006-02-21 23:47:00 +0000184 /* Verify that we can handle the request. */
185 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
186 pjsua.endpt, &response);
187 if (status != PJ_SUCCESS) {
Benny Prijono84126ab2006-02-09 09:30:09 +0000188
Benny Prijono26ff9062006-02-21 23:47:00 +0000189 /*
190 * No we can't handle the incoming INVITE request.
191 */
Benny Prijono84126ab2006-02-09 09:30:09 +0000192
Benny Prijono26ff9062006-02-21 23:47:00 +0000193 if (response) {
194 pjsip_response_addr res_addr;
Benny Prijono84126ab2006-02-09 09:30:09 +0000195
Benny Prijono26ff9062006-02-21 23:47:00 +0000196 pjsip_get_response_addr(response->pool, rdata, &res_addr);
197 pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,
198 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000199
200 } else {
Benny Prijono84126ab2006-02-09 09:30:09 +0000201
Benny Prijono26ff9062006-02-21 23:47:00 +0000202 /* Respond with 500 (Internal Server Error) */
203 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
204 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000205 }
206
Benny Prijono26ff9062006-02-21 23:47:00 +0000207 return PJ_TRUE;
208 }
209
210
211 /*
212 * Yes we can handle the incoming INVITE request.
213 */
214
215 /* Find free call slot. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000216 for (call_index=0; call_index < pjsua.max_calls; ++call_index) {
217 if (pjsua.calls[call_index].inv == NULL)
Benny Prijono26ff9062006-02-21 23:47:00 +0000218 break;
219 }
220
Benny Prijonoa91a0032006-02-26 21:23:45 +0000221 if (call_index == PJSUA_MAX_CALLS) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000222 pjsip_endpt_respond_stateless(pjsua.endpt, rdata,
223 PJSIP_SC_BUSY_HERE, NULL,
224 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000225 return PJ_TRUE;
226 }
227
Benny Prijono26ff9062006-02-21 23:47:00 +0000228
Benny Prijono26ff9062006-02-21 23:47:00 +0000229 /* Get media capability from media endpoint: */
230
Benny Prijonoa91a0032006-02-26 21:23:45 +0000231 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 1,
232 &pjsua.calls[call_index].skinfo,
Benny Prijono26ff9062006-02-21 23:47:00 +0000233 &answer );
234 if (status != PJ_SUCCESS) {
235 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
236 NULL, NULL);
237
Benny Prijono26ff9062006-02-21 23:47:00 +0000238 return PJ_TRUE;
239 }
240
Benny Prijonoa91a0032006-02-26 21:23:45 +0000241 /* TODO:
242 *
243 * Get which account is most likely to be associated with this incoming
244 * call. We need the account to find which contact URI to put for
245 * the call.
246 */
247 acc_index = 0;
248
Benny Prijono26ff9062006-02-21 23:47:00 +0000249 /* Create dialog: */
250
251 status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000252 &pjsua.acc[acc_index].contact_uri,
253 &dlg);
Benny Prijono26ff9062006-02-21 23:47:00 +0000254 if (status != PJ_SUCCESS) {
255 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
256 NULL, NULL);
257
Benny Prijono26ff9062006-02-21 23:47:00 +0000258 return PJ_TRUE;
259 }
260
261
262 /* Create invite session: */
263
264 status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
265 if (status != PJ_SUCCESS) {
266
Benny Prijonob0808372006-03-02 21:18:58 +0000267 pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000268 pjsip_dlg_terminate(dlg);
Benny Prijono26ff9062006-02-21 23:47:00 +0000269 return PJ_TRUE;
270 }
271
272
273 /* Create and attach pjsua data to the dialog: */
274
Benny Prijonoa91a0032006-02-26 21:23:45 +0000275 pjsua.calls[call_index].inv = inv;
Benny Prijono26ff9062006-02-21 23:47:00 +0000276
Benny Prijonoa91a0032006-02-26 21:23:45 +0000277 dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
278 inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +0000279
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,
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000286 (pjsua.auto_answer ? pjsua.auto_answer
287 : 100),
Benny Prijono64f851e2006-02-23 13:49:28 +0000288 NULL, NULL, &response);
Benny Prijono26ff9062006-02-21 23:47:00 +0000289 if (status != PJ_SUCCESS) {
290
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000291 int st_code;
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000292
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000293 pjsua_perror(THIS_FILE, "Unable to send answer to incoming INVITE",
294 status);
295
296 /* If failed to send 2xx response, there's a good chance that it is
297 * because SDP negotiation has failed.
298 */
299 if (pjsua.auto_answer/100 == 2)
300 st_code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
301 else
302 st_code = 500;
303
304 pjsip_dlg_respond(dlg, rdata, st_code, NULL, NULL, NULL);
305 pjsip_inv_terminate(inv, st_code, PJ_FALSE);
306 return PJ_TRUE;
Benny Prijono26ff9062006-02-21 23:47:00 +0000307
308 } else {
Benny Prijono64f851e2006-02-23 13:49:28 +0000309 status = pjsip_inv_send_msg(inv, response, NULL);
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000310 if (status != PJ_SUCCESS)
311 pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
Benny Prijono26ff9062006-02-21 23:47:00 +0000312 }
313
Benny Prijono64f851e2006-02-23 13:49:28 +0000314 if (pjsua.auto_answer < 200) {
315 PJ_LOG(3,(THIS_FILE,
316 "\nIncoming call!!\n"
317 "From: %.*s\n"
318 "To: %.*s\n"
319 "(press 'a' to answer, 'h' to decline)",
320 (int)dlg->remote.info_str.slen,
321 dlg->remote.info_str.ptr,
322 (int)dlg->local.info_str.slen,
323 dlg->local.info_str.ptr));
324 } else {
325 PJ_LOG(3,(THIS_FILE,
326 "Call From:%.*s To:%.*s was answered with %d (%s)",
327 (int)dlg->remote.info_str.slen,
328 dlg->remote.info_str.ptr,
329 (int)dlg->local.info_str.slen,
330 dlg->local.info_str.ptr,
331 pjsua.auto_answer,
332 pjsip_get_status_text(pjsua.auto_answer)->ptr ));
333 }
334
Benny Prijonoa91a0032006-02-26 21:23:45 +0000335 ++pjsua.call_cnt;
336
Benny Prijono26ff9062006-02-21 23:47:00 +0000337 /* This INVITE request has been handled. */
338 return PJ_TRUE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000339}
340
341
342/*
343 * This callback receives notification from invite session when the
344 * session state has changed.
345 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000346static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
347 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000348{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000349 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000350
351 /* If this is an outgoing INVITE that was created because of
352 * REFER/transfer, send NOTIFY to transferer.
353 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000354 if (call && call->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000355 int st_code = -1;
356 pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
357
358
Benny Prijonoa91a0032006-02-26 21:23:45 +0000359 switch (call->inv->state) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000360 case PJSIP_INV_STATE_NULL:
361 case PJSIP_INV_STATE_CALLING:
362 /* Do nothing */
363 break;
364
365 case PJSIP_INV_STATE_EARLY:
366 case PJSIP_INV_STATE_CONNECTING:
367 st_code = e->body.tsx_state.tsx->status_code;
368 ev_state = PJSIP_EVSUB_STATE_ACTIVE;
369 break;
370
371 case PJSIP_INV_STATE_CONFIRMED:
372 /* When state is confirmed, send the final 200/OK and terminate
373 * subscription.
374 */
375 st_code = e->body.tsx_state.tsx->status_code;
376 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
377 break;
378
379 case PJSIP_INV_STATE_DISCONNECTED:
380 st_code = e->body.tsx_state.tsx->status_code;
381 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
382 break;
383 }
384
385 if (st_code != -1) {
386 pjsip_tx_data *tdata;
387 pj_status_t status;
388
Benny Prijonoa91a0032006-02-26 21:23:45 +0000389 status = pjsip_xfer_notify( call->xfer_sub,
Benny Prijono26ff9062006-02-21 23:47:00 +0000390 ev_state, st_code,
391 NULL, &tdata);
392 if (status != PJ_SUCCESS) {
393 pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);
394 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000395 status = pjsip_xfer_send_request(call->xfer_sub, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +0000396 if (status != PJ_SUCCESS) {
397 pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);
398 }
399 }
400 }
401 }
402
Benny Prijono84126ab2006-02-09 09:30:09 +0000403
Benny Prijonob0808372006-03-02 21:18:58 +0000404 pjsua_ui_on_call_state(call->index, e);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000405
406 /* call->inv may be NULL now */
407
Benny Prijono84126ab2006-02-09 09:30:09 +0000408 /* Destroy media session when invite session is disconnected. */
409 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono632ce712006-02-09 14:01:40 +0000410
Benny Prijonoa91a0032006-02-26 21:23:45 +0000411 pj_assert(call != NULL);
Benny Prijono632ce712006-02-09 14:01:40 +0000412
Benny Prijonoa91a0032006-02-26 21:23:45 +0000413 if (call && call->session) {
414 pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
415 pjmedia_session_destroy(call->session);
416 call->session = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +0000417
418 PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
419 }
420
Benny Prijonoa91a0032006-02-26 21:23:45 +0000421 call->inv = NULL;
422 --pjsua.call_cnt;
Benny Prijono84126ab2006-02-09 09:30:09 +0000423 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000424}
425
426
427/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000428 * Callback called by event framework when the xfer subscription state
429 * has changed.
430 */
431static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
432{
433
434 PJ_UNUSED_ARG(event);
435
436 /*
437 * We're only interested when subscription is terminated, to
438 * clear the xfer_sub member of the inv_data.
439 */
440 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000441 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000442
Benny Prijonoa91a0032006-02-26 21:23:45 +0000443 call = pjsip_evsub_get_mod_data(sub, pjsua.mod.id);
444 if (!call)
Benny Prijono26ff9062006-02-21 23:47:00 +0000445 return;
446
447 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000448 call->xfer_sub = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +0000449
450 PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated"));
451 }
452}
453
454
455/*
456 * Follow transfer (REFER) request.
457 */
458static void on_call_transfered( pjsip_inv_session *inv,
459 pjsip_rx_data *rdata )
460{
461 pj_status_t status;
462 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000463 pjsua_call *existing_call;
464 int new_call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000465 const pj_str_t str_refer_to = { "Refer-To", 8};
466 pjsip_generic_string_hdr *refer_to;
467 char *uri;
468 struct pjsip_evsub_user xfer_cb;
469 pjsip_evsub *sub;
470
Benny Prijonoa91a0032006-02-26 21:23:45 +0000471 existing_call = inv->dlg->mod_data[pjsua.mod.id];
472
Benny Prijono26ff9062006-02-21 23:47:00 +0000473 /* Find the Refer-To header */
474 refer_to = (pjsip_generic_string_hdr*)
475 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
476
477 if (refer_to == NULL) {
478 /* Invalid Request.
479 * No Refer-To header!
480 */
481 PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!"));
Benny Prijonob0808372006-03-02 21:18:58 +0000482 pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000483 return;
484 }
485
486 PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s",
487 (int)inv->dlg->remote.info_str.slen,
488 inv->dlg->remote.info_str.ptr,
489 (int)refer_to->hvalue.slen,
490 refer_to->hvalue.ptr));
491
492 /* Init callback */
493 pj_memset(&xfer_cb, 0, sizeof(xfer_cb));
494 xfer_cb.on_evsub_state = &xfer_on_evsub_state;
495
496 /* Create transferee event subscription */
497 status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
498 if (status != PJ_SUCCESS) {
499 pjsua_perror(THIS_FILE, "Unable to create xfer uas", status);
Benny Prijonob0808372006-03-02 21:18:58 +0000500 pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000501 return;
502 }
503
504 /* Accept the REFER request, send 200 (OK). */
505 pjsip_xfer_accept(sub, rdata, 200, NULL);
506
507 /* Create initial NOTIFY request */
508 status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
509 100, NULL, &tdata);
510 if (status != PJ_SUCCESS) {
511 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status);
512 return;
513 }
514
515 /* Send initial NOTIFY request */
516 status = pjsip_xfer_send_request( sub, tdata);
517 if (status != PJ_SUCCESS) {
518 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status);
519 return;
520 }
521
522 /* We're cheating here.
523 * We need to get a null terminated string from a pj_str_t.
524 * So grab the pointer from the hvalue and NULL terminate it, knowing
525 * that the NULL position will be occupied by a newline.
526 */
527 uri = refer_to->hvalue.ptr;
528 uri[refer_to->hvalue.slen] = '\0';
529
530 /* Now make the outgoing call. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000531 status = pjsua_make_call(existing_call->acc_index, uri, &new_call);
Benny Prijono26ff9062006-02-21 23:47:00 +0000532 if (status != PJ_SUCCESS) {
533
534 /* Notify xferer about the error */
535 status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
536 500, NULL, &tdata);
537 if (status != PJ_SUCCESS) {
538 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",
539 status);
540 return;
541 }
542 status = pjsip_xfer_send_request(sub, tdata);
543 if (status != PJ_SUCCESS) {
544 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",
545 status);
546 return;
547 }
548 return;
549 }
550
551 /* Put the server subscription in inv_data.
552 * Subsequent state changed in pjsua_inv_on_state_changed() will be
553 * reported back to the server subscription.
554 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000555 pjsua.calls[new_call].xfer_sub = sub;
Benny Prijono26ff9062006-02-21 23:47:00 +0000556
557 /* Put the invite_data in the subscription. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000558 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, &pjsua.calls[new_call]);
Benny Prijono26ff9062006-02-21 23:47:00 +0000559}
560
561
562/*
563 * This callback is called when transaction state has changed in INVITE
Benny Prijonob0808372006-03-02 21:18:58 +0000564 * session. We use this to trap:
565 * - incoming REFER request.
566 * - incoming MESSAGE request.
Benny Prijono26ff9062006-02-21 23:47:00 +0000567 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000568static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
569 pjsip_transaction *tsx,
570 pjsip_event *e)
Benny Prijono26ff9062006-02-21 23:47:00 +0000571{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000572 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
573
Benny Prijono26ff9062006-02-21 23:47:00 +0000574 if (tsx->role==PJSIP_ROLE_UAS &&
575 tsx->state==PJSIP_TSX_STATE_TRYING &&
576 pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0)
577 {
578 /*
579 * Incoming REFER request.
580 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000581 on_call_transfered(call->inv, e->body.tsx_state.src.rdata);
Benny Prijonob0808372006-03-02 21:18:58 +0000582
Benny Prijono26ff9062006-02-21 23:47:00 +0000583 }
Benny Prijonob0808372006-03-02 21:18:58 +0000584 else if (tsx->role==PJSIP_ROLE_UAS &&
585 tsx->state==PJSIP_TSX_STATE_TRYING &&
586 pjsip_method_cmp(&tsx->method, &pjsip_message_method)==0)
587 {
588 /*
589 * Incoming MESSAGE request!
590 */
591 pjsip_rx_data *rdata;
592 pjsip_msg *msg;
593 pjsip_accept_hdr *accept_hdr;
594 pj_status_t status;
595
596 rdata = e->body.tsx_state.src.rdata;
597 msg = rdata->msg_info.msg;
598
599 /* Request MUST have message body, with Content-Type equal to
600 * "text/plain".
601 */
602 if (pjsua_im_accept_pager(rdata, &accept_hdr) == PJ_FALSE) {
603
604 pjsip_hdr hdr_list;
605
606 pj_list_init(&hdr_list);
607 pj_list_push_back(&hdr_list, accept_hdr);
608
609 pjsip_dlg_respond( inv->dlg, rdata, PJSIP_SC_NOT_ACCEPTABLE_HERE,
610 NULL, &hdr_list, NULL );
611 return;
612 }
613
614 /* Respond with 200 first, so that remote doesn't retransmit in case
615 * the UI takes too long to process the message.
616 */
617 status = pjsip_dlg_respond( inv->dlg, rdata, 200, NULL, NULL, NULL);
618
619 /* Process MESSAGE request */
620 pjsua_im_process_pager(call->index, &inv->dlg->remote.info_str,
621 &inv->dlg->local.info_str, rdata);
622 }
623
Benny Prijono26ff9062006-02-21 23:47:00 +0000624}
625
626
627/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000628 * This callback is called by invite session framework when UAC session
629 * has forked.
630 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000631static void pjsua_call_on_forked( pjsip_inv_session *inv,
632 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000633{
634 PJ_UNUSED_ARG(inv);
635 PJ_UNUSED_ARG(e);
636
637 PJ_TODO(HANDLE_FORKED_DIALOG);
638}
639
640
641/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000642 * Create inactive SDP for call hold.
643 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000644static pj_status_t create_inactive_sdp(pjsua_call *call,
Benny Prijono26ff9062006-02-21 23:47:00 +0000645 pjmedia_sdp_session **p_answer)
646{
647 pj_status_t status;
648 pjmedia_sdp_conn *conn;
649 pjmedia_sdp_attr *attr;
650 pjmedia_sdp_session *sdp;
651
652 /* Create new offer */
653 status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000654 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +0000655 if (status != PJ_SUCCESS) {
656 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
657 return status;
658 }
659
660 /* Get SDP media connection line */
661 conn = sdp->media[0]->conn;
662 if (!conn)
663 conn = sdp->conn;
664
665 /* Modify address */
666 conn->addr = pj_str("0.0.0.0");
667
668 /* Remove existing directions attributes */
669 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
670 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
671 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
672 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
673
674 /* Add inactive attribute */
675 attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL);
676 pjmedia_sdp_media_add_attr(sdp->media[0], attr);
677
678 *p_answer = sdp;
679
680 return status;
681}
682
683/*
684 * Called when session received new offer.
685 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000686static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
687 const pjmedia_sdp_session *offer)
Benny Prijono26ff9062006-02-21 23:47:00 +0000688{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000689 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000690 pjmedia_sdp_conn *conn;
691 pjmedia_sdp_session *answer;
692 pj_bool_t is_remote_active;
693 pj_status_t status;
694
Benny Prijonoa91a0032006-02-26 21:23:45 +0000695 call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000696
697 /*
698 * See if remote is offering active media (i.e. not on-hold)
699 */
700 is_remote_active = PJ_TRUE;
701
702 conn = offer->media[0]->conn;
703 if (!conn)
704 conn = offer->conn;
705
706 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
707 pj_strcmp2(&conn->addr, "0")==0)
708 {
709 is_remote_active = PJ_FALSE;
710
711 }
712 else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))
713 {
714 is_remote_active = PJ_FALSE;
715 }
716
717 PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s",
718 (is_remote_active ? "active" : "inactive")));
719
720 /* Supply candidate answer */
721 if (is_remote_active) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000722 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
723 &call->skinfo, &answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000724 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000725 status = create_inactive_sdp( call, &answer );
Benny Prijono26ff9062006-02-21 23:47:00 +0000726 }
727
728 if (status != PJ_SUCCESS) {
729 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
730 return;
731 }
732
Benny Prijonoa91a0032006-02-26 21:23:45 +0000733 status = pjsip_inv_set_sdp_answer(call->inv, answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000734 if (status != PJ_SUCCESS) {
735 pjsua_perror(THIS_FILE, "Unable to set answer", status);
736 return;
737 }
738
739}
740
Benny Prijono1c2bf462006-03-05 11:54:02 +0000741/* Disconnect call */
742static void call_disconnect(pjsip_inv_session *inv,
743 int st_code)
744{
745 pjsip_tx_data *tdata;
746 pj_status_t status;
747
748 status = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
749 if (status == PJ_SUCCESS)
750 status = pjsip_inv_send_msg(inv, tdata, NULL);
751
752 if (status != PJ_SUCCESS) {
753 pjsua_perror(THIS_FILE, "Unable to disconnect call", status);
754 }
755}
Benny Prijono26ff9062006-02-21 23:47:00 +0000756
757/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000758 * Callback to be called when SDP offer/answer negotiation has just completed
759 * in the session. This function will start/update media if negotiation
760 * has succeeded.
761 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000762static void pjsua_call_on_media_update(pjsip_inv_session *inv,
763 pj_status_t status)
Benny Prijono84126ab2006-02-09 09:30:09 +0000764{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000765 pjsua_call *call;
Benny Prijono84126ab2006-02-09 09:30:09 +0000766 const pjmedia_sdp_session *local_sdp;
767 const pjmedia_sdp_session *remote_sdp;
Benny Prijono26ff9062006-02-21 23:47:00 +0000768 pjmedia_port *media_port;
769 pj_str_t port_name;
770 char tmp[PJSIP_MAX_URL_SIZE];
Benny Prijono84126ab2006-02-09 09:30:09 +0000771
Benny Prijonoa91a0032006-02-26 21:23:45 +0000772 call = inv->dlg->mod_data[pjsua.mod.id];
773
Benny Prijono84126ab2006-02-09 09:30:09 +0000774 if (status != PJ_SUCCESS) {
775
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000776 pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000777
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000778 /* Disconnect call if we're not in the middle of initializing an
779 * UAS dialog and if this is not a re-INVITE
780 */
781 if (inv->state != PJSIP_INV_STATE_NULL &&
782 inv->state != PJSIP_INV_STATE_CONFIRMED)
783 {
Benny Prijono1c2bf462006-03-05 11:54:02 +0000784 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
785 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000786 return;
787
788 }
789
790 /* Destroy existing media session, if any. */
791
Benny Prijonoa91a0032006-02-26 21:23:45 +0000792 if (call && call->session) {
793 pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
794 pjmedia_session_destroy(call->session);
795 call->session = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +0000796 }
797
798 /* Get local and remote SDP */
799
Benny Prijonoa91a0032006-02-26 21:23:45 +0000800 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000801 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000802 pjsua_perror(THIS_FILE,
803 "Unable to retrieve currently active local SDP",
804 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000805 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000806 return;
807 }
808
809
Benny Prijonoa91a0032006-02-26 21:23:45 +0000810 status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000811 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000812 pjsua_perror(THIS_FILE,
813 "Unable to retrieve currently active remote SDP",
814 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000815 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000816 return;
817 }
818
Benny Prijono84126ab2006-02-09 09:30:09 +0000819 /* Create new media session.
820 * The media session is active immediately.
821 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000822 if (pjsua.null_audio)
823 return;
824
825 status = pjmedia_session_create( pjsua.med_endpt, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000826 &call->skinfo,
Benny Prijono26ff9062006-02-21 23:47:00 +0000827 local_sdp, remote_sdp,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000828 call,
829 &call->session );
Benny Prijono26ff9062006-02-21 23:47:00 +0000830 if (status != PJ_SUCCESS) {
831 pjsua_perror(THIS_FILE, "Unable to create media session",
832 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000833 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono26ff9062006-02-21 23:47:00 +0000834 return;
Benny Prijono84126ab2006-02-09 09:30:09 +0000835 }
Benny Prijono26ff9062006-02-21 23:47:00 +0000836
837
838 /* Get the port interface of the first stream in the session.
839 * We need the port interface to add to the conference bridge.
840 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000841 pjmedia_session_get_port(call->session, 0, &media_port);
Benny Prijono26ff9062006-02-21 23:47:00 +0000842
843
844 /*
845 * Add the call to conference bridge.
846 */
847 port_name.ptr = tmp;
848 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000849 call->inv->dlg->remote.info->uri,
Benny Prijono26ff9062006-02-21 23:47:00 +0000850 tmp, sizeof(tmp));
851 if (port_name.slen < 1) {
852 port_name = pj_str("call");
853 }
Benny Prijonoa91a0032006-02-26 21:23:45 +0000854 status = pjmedia_conf_add_port( pjsua.mconf, call->inv->pool,
Benny Prijono26ff9062006-02-21 23:47:00 +0000855 media_port,
856 &port_name,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000857 &call->conf_slot);
Benny Prijono26ff9062006-02-21 23:47:00 +0000858 if (status != PJ_SUCCESS) {
859 pjsua_perror(THIS_FILE, "Unable to create conference slot",
860 status);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000861 pjmedia_session_destroy(call->session);
862 call->session = NULL;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000863 call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR);
Benny Prijono26ff9062006-02-21 23:47:00 +0000864 return;
865 }
866
Benny Prijono64f851e2006-02-23 13:49:28 +0000867 /* If auto-play is configured, connect the call to the file player
868 * port
Benny Prijono26ff9062006-02-21 23:47:00 +0000869 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000870 if (pjsua.auto_play && pjsua.wav_file &&
871 call->inv->role == PJSIP_ROLE_UAS)
872 {
Benny Prijono64f851e2006-02-23 13:49:28 +0000873
874 pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000875 call->conf_slot);
876
877 } else if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) {
878
879 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
880 call->conf_slot);
881
882 } else if (pjsua.auto_conf) {
883
884 int i;
885
886 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot);
887 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0);
888
889 for (i=0; i < pjsua.max_calls; ++i) {
890
891 if (!pjsua.calls[i].session)
892 continue;
893
894 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
895 pjsua.calls[i].conf_slot);
896 pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot,
897 call->conf_slot);
898 }
Benny Prijono64f851e2006-02-23 13:49:28 +0000899
900 } else {
901
902 /* Connect new call to the sound device port (port zero) in the
903 * main conference bridge.
904 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000905 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot);
906 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0);
Benny Prijono64f851e2006-02-23 13:49:28 +0000907 }
908
Benny Prijono26ff9062006-02-21 23:47:00 +0000909
910 /* Done. */
911 {
912 struct pjmedia_session_info sess_info;
913 char info[80];
914 int info_len = 0;
915 unsigned i;
916
Benny Prijonoa91a0032006-02-26 21:23:45 +0000917 pjmedia_session_get_info(call->session, &sess_info);
Benny Prijono26ff9062006-02-21 23:47:00 +0000918 for (i=0; i<sess_info.stream_cnt; ++i) {
919 int len;
920 const char *dir;
921 pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
922
923 switch (strm_info->dir) {
924 case PJMEDIA_DIR_NONE:
925 dir = "inactive";
926 break;
927 case PJMEDIA_DIR_ENCODING:
928 dir = "sendonly";
929 break;
930 case PJMEDIA_DIR_DECODING:
931 dir = "recvonly";
932 break;
933 case PJMEDIA_DIR_ENCODING_DECODING:
934 dir = "sendrecv";
935 break;
936 default:
937 dir = "unknown";
938 break;
939 }
940 len = pj_ansi_sprintf( info+info_len,
941 ", stream #%d: %.*s (%s)", i,
942 (int)strm_info->fmt.encoding_name.slen,
Benny Prijonoab7399b2006-02-27 00:40:31 +0000943 strm_info->fmt.encoding_name.ptr,
Benny Prijono26ff9062006-02-21 23:47:00 +0000944 dir);
945 if (len > 0)
946 info_len += len;
947 }
948 PJ_LOG(3,(THIS_FILE,"Media started%s", info));
949 }
950}
951
952
953/*
954 * Hangup call.
955 */
Benny Prijono1c2bf462006-03-05 11:54:02 +0000956void pjsua_call_hangup(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +0000957{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000958 pjsua_call *call;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000959 int code;
Benny Prijono26ff9062006-02-21 23:47:00 +0000960 pj_status_t status;
961 pjsip_tx_data *tdata;
962
Benny Prijonoa91a0032006-02-26 21:23:45 +0000963
964 call = &pjsua.calls[call_index];
965
966 if (!call->inv) {
967 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
968 return;
969 }
970
Benny Prijono1c2bf462006-03-05 11:54:02 +0000971 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
972 code = PJSIP_SC_OK;
973 else if (call->inv->role == PJSIP_ROLE_UAS)
974 code = PJSIP_SC_DECLINE;
975 else
976 code = PJSIP_SC_REQUEST_TERMINATED;
977
Benny Prijonoa91a0032006-02-26 21:23:45 +0000978 status = pjsip_inv_end_session(call->inv, code, NULL, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +0000979 if (status != PJ_SUCCESS) {
980 pjsua_perror(THIS_FILE,
981 "Failed to create end session message",
982 status);
983 return;
984 }
985
Benny Prijonofccab712006-02-22 22:23:22 +0000986 /* pjsip_inv_end_session may return PJ_SUCCESS with NULL
987 * as p_tdata when INVITE transaction has not been answered
988 * with any provisional responses.
989 */
990 if (tdata == NULL)
991 return;
992
Benny Prijonoa91a0032006-02-26 21:23:45 +0000993 status = pjsip_inv_send_msg(call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000994 if (status != PJ_SUCCESS) {
995 pjsua_perror(THIS_FILE,
996 "Failed to send end session message",
997 status);
998 return;
999 }
1000}
1001
1002
1003/*
1004 * Put call on-Hold.
1005 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001006void pjsua_call_set_hold(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001007{
1008 pjmedia_sdp_session *sdp;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001009 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001010 pjsip_tx_data *tdata;
1011 pj_status_t status;
1012
Benny Prijonoa91a0032006-02-26 21:23:45 +00001013 call = &pjsua.calls[call_index];
1014
1015 if (!call->inv) {
1016 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1017 return;
1018 }
1019
1020 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001021 PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
1022 return;
1023 }
1024
Benny Prijonoa91a0032006-02-26 21:23:45 +00001025 status = create_inactive_sdp(call, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001026 if (status != PJ_SUCCESS)
1027 return;
1028
1029 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001030 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001031 if (status != PJ_SUCCESS) {
1032 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1033 return;
1034 }
1035
Benny Prijonoa91a0032006-02-26 21:23:45 +00001036 status = pjsip_inv_send_msg( call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +00001037 if (status != PJ_SUCCESS) {
1038 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1039 return;
1040 }
1041}
1042
1043
1044/*
1045 * re-INVITE.
1046 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001047void pjsua_call_reinvite(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001048{
1049 pjmedia_sdp_session *sdp;
1050 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001051 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001052 pj_status_t status;
1053
Benny Prijonoa91a0032006-02-26 21:23:45 +00001054 call = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +00001055
Benny Prijonoa91a0032006-02-26 21:23:45 +00001056 if (!call->inv) {
1057 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1058 return;
1059 }
1060
1061
1062 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001063 PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
1064 return;
1065 }
1066
1067 /* Create SDP */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001068 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
1069 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001070 if (status != PJ_SUCCESS) {
Benny Prijonoa91a0032006-02-26 21:23:45 +00001071 pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",
1072 status);
Benny Prijono26ff9062006-02-21 23:47:00 +00001073 return;
1074 }
1075
1076 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001077 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001078 if (status != PJ_SUCCESS) {
1079 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1080 return;
1081 }
1082
Benny Prijonoa91a0032006-02-26 21:23:45 +00001083 status = pjsip_inv_send_msg( call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +00001084 if (status != PJ_SUCCESS) {
1085 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1086 return;
1087 }
1088}
1089
1090
1091/*
1092 * Transfer call.
1093 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001094void pjsua_call_xfer(int call_index, const char *dest)
Benny Prijono26ff9062006-02-21 23:47:00 +00001095{
1096 pjsip_evsub *sub;
1097 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001098 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001099 pj_str_t tmp;
1100 pj_status_t status;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001101
Benny Prijono26ff9062006-02-21 23:47:00 +00001102
Benny Prijonoa91a0032006-02-26 21:23:45 +00001103 call = &pjsua.calls[call_index];
1104
1105 if (!call->inv) {
1106 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1107 return;
1108 }
1109
Benny Prijono26ff9062006-02-21 23:47:00 +00001110 /* Create xfer client subscription.
1111 * We're not interested in knowing the transfer result, so we
1112 * put NULL as the callback.
1113 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001114 status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub);
Benny Prijono26ff9062006-02-21 23:47:00 +00001115 if (status != PJ_SUCCESS) {
1116 pjsua_perror(THIS_FILE, "Unable to create xfer", status);
1117 return;
1118 }
1119
1120 /*
1121 * Create REFER request.
1122 */
1123 status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
1124 if (status != PJ_SUCCESS) {
1125 pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
1126 return;
1127 }
1128
1129 /* Send. */
1130 status = pjsip_xfer_send_request(sub, tdata);
1131 if (status != PJ_SUCCESS) {
1132 pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
1133 return;
1134 }
1135
1136 /* For simplicity (that's what this program is intended to be!),
1137 * leave the original invite session as it is. More advanced application
1138 * may want to hold the INVITE, or terminate the invite, or whatever.
1139 */
Benny Prijono84126ab2006-02-09 09:30:09 +00001140}
Benny Prijono834aee32006-02-19 01:38:06 +00001141
1142
Benny Prijonob0808372006-03-02 21:18:58 +00001143/**
1144 * Send instant messaging inside INVITE session.
1145 */
1146void pjsua_call_send_im(int call_index, const char *str)
1147{
1148 pjsua_call *call;
1149 const pj_str_t mime_text = pj_str("text");
1150 const pj_str_t mime_plain = pj_str("plain");
1151 pj_str_t text;
1152 pjsip_tx_data *tdata;
1153 pj_status_t status;
1154
1155 call = &pjsua.calls[call_index];
1156
1157 if (!call->inv) {
1158 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1159 return;
1160 }
1161
1162 /* Lock dialog. */
1163 pjsip_dlg_inc_lock(call->inv->dlg);
1164
1165 /* Create request message. */
1166 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1167 -1, &tdata);
1168 if (status != PJ_SUCCESS) {
1169 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1170 goto on_return;
1171 }
1172
1173 /* Add accept header. */
1174 pjsip_msg_add_hdr( tdata->msg,
1175 (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
1176
1177 /* Create "text/plain" message body. */
1178 tdata->msg->body = pjsip_msg_body_create( tdata->pool, &mime_text,
1179 &mime_plain,
1180 pj_cstr(&text, str));
1181 if (tdata->msg->body == NULL) {
1182 pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM);
1183 pjsip_tx_data_dec_ref(tdata);
1184 goto on_return;
1185 }
1186
1187 /* Send the request. */
1188 status = pjsip_dlg_send_request( call->inv->dlg, tdata, NULL);
1189 if (status != PJ_SUCCESS) {
1190 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1191 goto on_return;
1192 }
1193
1194on_return:
1195 pjsip_dlg_dec_lock(call->inv->dlg);
1196}
1197
1198
1199/**
1200 * Send IM typing indication inside INVITE session.
1201 */
1202void pjsua_call_typing(int call_index, pj_bool_t is_typing)
1203{
1204 pjsua_call *call;
1205 pjsip_tx_data *tdata;
1206 pj_status_t status;
1207
1208 call = &pjsua.calls[call_index];
1209
1210 if (!call->inv) {
1211 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1212 return;
1213 }
1214
1215 /* Lock dialog. */
1216 pjsip_dlg_inc_lock(call->inv->dlg);
1217
1218 /* Create request message. */
1219 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1220 -1, &tdata);
1221 if (status != PJ_SUCCESS) {
1222 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1223 goto on_return;
1224 }
1225
1226 /* Create "application/im-iscomposing+xml" msg body. */
1227 tdata->msg->body = pjsip_iscomposing_create_body(tdata->pool, is_typing,
1228 NULL, NULL, -1);
1229
1230 /* Send the request. */
1231 status = pjsip_dlg_send_request( call->inv->dlg, tdata, NULL);
1232 if (status != PJ_SUCCESS) {
1233 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1234 goto on_return;
1235 }
1236
1237on_return:
1238 pjsip_dlg_dec_lock(call->inv->dlg);}
1239
1240
Benny Prijono834aee32006-02-19 01:38:06 +00001241/*
1242 * Terminate all calls.
1243 */
Benny Prijono1c2bf462006-03-05 11:54:02 +00001244void pjsua_call_hangup_all(void)
Benny Prijono834aee32006-02-19 01:38:06 +00001245{
Benny Prijonoa91a0032006-02-26 21:23:45 +00001246 int i;
Benny Prijono834aee32006-02-19 01:38:06 +00001247
Benny Prijonoa91a0032006-02-26 21:23:45 +00001248 for (i=0; i<pjsua.max_calls; ++i) {
Benny Prijono834aee32006-02-19 01:38:06 +00001249 pjsip_tx_data *tdata;
Benny Prijono1c2bf462006-03-05 11:54:02 +00001250 int st_code;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001251 pjsua_call *call;
Benny Prijono834aee32006-02-19 01:38:06 +00001252
Benny Prijonoa91a0032006-02-26 21:23:45 +00001253 if (pjsua.calls[i].inv == NULL)
1254 continue;
Benny Prijono834aee32006-02-19 01:38:06 +00001255
Benny Prijonoa91a0032006-02-26 21:23:45 +00001256 call = &pjsua.calls[i];
1257
Benny Prijono1c2bf462006-03-05 11:54:02 +00001258 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
1259 st_code = 200;
1260 } else {
1261 st_code = PJSIP_SC_GONE;
1262 }
1263
1264 if (pjsip_inv_end_session(call->inv, st_code, NULL, &tdata)==0) {
Benny Prijonofccab712006-02-22 22:23:22 +00001265 if (tdata)
Benny Prijonoa91a0032006-02-26 21:23:45 +00001266 pjsip_inv_send_msg(call->inv, tdata, NULL);
Benny Prijonofccab712006-02-22 22:23:22 +00001267 }
Benny Prijono834aee32006-02-19 01:38:06 +00001268 }
1269}
1270
Benny Prijono26ff9062006-02-21 23:47:00 +00001271
Benny Prijonoa91a0032006-02-26 21:23:45 +00001272pj_status_t pjsua_call_init(void)
1273{
1274 /* Initialize invite session callback. */
1275 pjsip_inv_callback inv_cb;
1276 pj_status_t status;
1277
1278 pj_memset(&inv_cb, 0, sizeof(inv_cb));
1279 inv_cb.on_state_changed = &pjsua_call_on_state_changed;
1280 inv_cb.on_new_session = &pjsua_call_on_forked;
1281 inv_cb.on_media_update = &pjsua_call_on_media_update;
1282 inv_cb.on_rx_offer = &pjsua_call_on_rx_offer;
1283 inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed;
1284
1285
1286 /* Initialize invite session module: */
1287 status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb);
1288
1289 return status;
1290}