blob: 1fc806046b533a5fcce7b847bcb7c7d8dd9c6b5c [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,
286 (pjsua.auto_answer ? 200 : 100),
287 NULL, NULL, &response);
Benny Prijono26ff9062006-02-21 23:47:00 +0000288 if (status != PJ_SUCCESS) {
289
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000290 pjsua_perror(THIS_FILE, "Unable to create 100 response", status);
291
Benny Prijonob0808372006-03-02 21:18:58 +0000292 pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000293 pjsip_inv_terminate(inv, 500, PJ_FALSE);
Benny Prijono26ff9062006-02-21 23:47:00 +0000294
295 } else {
Benny Prijono64f851e2006-02-23 13:49:28 +0000296 status = pjsip_inv_send_msg(inv, response, NULL);
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000297 if (status != PJ_SUCCESS)
298 pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
Benny Prijono26ff9062006-02-21 23:47:00 +0000299 }
300
Benny Prijono64f851e2006-02-23 13:49:28 +0000301 if (pjsua.auto_answer < 200) {
302 PJ_LOG(3,(THIS_FILE,
303 "\nIncoming call!!\n"
304 "From: %.*s\n"
305 "To: %.*s\n"
306 "(press 'a' to answer, 'h' to decline)",
307 (int)dlg->remote.info_str.slen,
308 dlg->remote.info_str.ptr,
309 (int)dlg->local.info_str.slen,
310 dlg->local.info_str.ptr));
311 } else {
312 PJ_LOG(3,(THIS_FILE,
313 "Call From:%.*s To:%.*s was answered with %d (%s)",
314 (int)dlg->remote.info_str.slen,
315 dlg->remote.info_str.ptr,
316 (int)dlg->local.info_str.slen,
317 dlg->local.info_str.ptr,
318 pjsua.auto_answer,
319 pjsip_get_status_text(pjsua.auto_answer)->ptr ));
320 }
321
Benny Prijonoa91a0032006-02-26 21:23:45 +0000322 ++pjsua.call_cnt;
323
Benny Prijono26ff9062006-02-21 23:47:00 +0000324 /* This INVITE request has been handled. */
325 return PJ_TRUE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000326}
327
328
329/*
330 * This callback receives notification from invite session when the
331 * session state has changed.
332 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000333static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
334 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000335{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000336 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000337
338 /* If this is an outgoing INVITE that was created because of
339 * REFER/transfer, send NOTIFY to transferer.
340 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000341 if (call && call->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000342 int st_code = -1;
343 pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
344
345
Benny Prijonoa91a0032006-02-26 21:23:45 +0000346 switch (call->inv->state) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000347 case PJSIP_INV_STATE_NULL:
348 case PJSIP_INV_STATE_CALLING:
349 /* Do nothing */
350 break;
351
352 case PJSIP_INV_STATE_EARLY:
353 case PJSIP_INV_STATE_CONNECTING:
354 st_code = e->body.tsx_state.tsx->status_code;
355 ev_state = PJSIP_EVSUB_STATE_ACTIVE;
356 break;
357
358 case PJSIP_INV_STATE_CONFIRMED:
359 /* When state is confirmed, send the final 200/OK and terminate
360 * subscription.
361 */
362 st_code = e->body.tsx_state.tsx->status_code;
363 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
364 break;
365
366 case PJSIP_INV_STATE_DISCONNECTED:
367 st_code = e->body.tsx_state.tsx->status_code;
368 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
369 break;
370 }
371
372 if (st_code != -1) {
373 pjsip_tx_data *tdata;
374 pj_status_t status;
375
Benny Prijonoa91a0032006-02-26 21:23:45 +0000376 status = pjsip_xfer_notify( call->xfer_sub,
Benny Prijono26ff9062006-02-21 23:47:00 +0000377 ev_state, st_code,
378 NULL, &tdata);
379 if (status != PJ_SUCCESS) {
380 pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);
381 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000382 status = pjsip_xfer_send_request(call->xfer_sub, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +0000383 if (status != PJ_SUCCESS) {
384 pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);
385 }
386 }
387 }
388 }
389
Benny Prijono84126ab2006-02-09 09:30:09 +0000390
Benny Prijonob0808372006-03-02 21:18:58 +0000391 pjsua_ui_on_call_state(call->index, e);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000392
393 /* call->inv may be NULL now */
394
Benny Prijono84126ab2006-02-09 09:30:09 +0000395 /* Destroy media session when invite session is disconnected. */
396 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono632ce712006-02-09 14:01:40 +0000397
Benny Prijonoa91a0032006-02-26 21:23:45 +0000398 pj_assert(call != NULL);
Benny Prijono632ce712006-02-09 14:01:40 +0000399
Benny Prijonoa91a0032006-02-26 21:23:45 +0000400 if (call && call->session) {
401 pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
402 pjmedia_session_destroy(call->session);
403 call->session = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +0000404
405 PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
406 }
407
Benny Prijonoa91a0032006-02-26 21:23:45 +0000408 call->inv = NULL;
409 --pjsua.call_cnt;
Benny Prijono84126ab2006-02-09 09:30:09 +0000410 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000411}
412
413
414/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000415 * Callback called by event framework when the xfer subscription state
416 * has changed.
417 */
418static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
419{
420
421 PJ_UNUSED_ARG(event);
422
423 /*
424 * We're only interested when subscription is terminated, to
425 * clear the xfer_sub member of the inv_data.
426 */
427 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000428 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000429
Benny Prijonoa91a0032006-02-26 21:23:45 +0000430 call = pjsip_evsub_get_mod_data(sub, pjsua.mod.id);
431 if (!call)
Benny Prijono26ff9062006-02-21 23:47:00 +0000432 return;
433
434 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000435 call->xfer_sub = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +0000436
437 PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated"));
438 }
439}
440
441
442/*
443 * Follow transfer (REFER) request.
444 */
445static void on_call_transfered( pjsip_inv_session *inv,
446 pjsip_rx_data *rdata )
447{
448 pj_status_t status;
449 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000450 pjsua_call *existing_call;
451 int new_call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000452 const pj_str_t str_refer_to = { "Refer-To", 8};
453 pjsip_generic_string_hdr *refer_to;
454 char *uri;
455 struct pjsip_evsub_user xfer_cb;
456 pjsip_evsub *sub;
457
Benny Prijonoa91a0032006-02-26 21:23:45 +0000458 existing_call = inv->dlg->mod_data[pjsua.mod.id];
459
Benny Prijono26ff9062006-02-21 23:47:00 +0000460 /* Find the Refer-To header */
461 refer_to = (pjsip_generic_string_hdr*)
462 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
463
464 if (refer_to == NULL) {
465 /* Invalid Request.
466 * No Refer-To header!
467 */
468 PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!"));
Benny Prijonob0808372006-03-02 21:18:58 +0000469 pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000470 return;
471 }
472
473 PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s",
474 (int)inv->dlg->remote.info_str.slen,
475 inv->dlg->remote.info_str.ptr,
476 (int)refer_to->hvalue.slen,
477 refer_to->hvalue.ptr));
478
479 /* Init callback */
480 pj_memset(&xfer_cb, 0, sizeof(xfer_cb));
481 xfer_cb.on_evsub_state = &xfer_on_evsub_state;
482
483 /* Create transferee event subscription */
484 status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
485 if (status != PJ_SUCCESS) {
486 pjsua_perror(THIS_FILE, "Unable to create xfer uas", status);
Benny Prijonob0808372006-03-02 21:18:58 +0000487 pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000488 return;
489 }
490
491 /* Accept the REFER request, send 200 (OK). */
492 pjsip_xfer_accept(sub, rdata, 200, NULL);
493
494 /* Create initial NOTIFY request */
495 status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
496 100, NULL, &tdata);
497 if (status != PJ_SUCCESS) {
498 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status);
499 return;
500 }
501
502 /* Send initial NOTIFY request */
503 status = pjsip_xfer_send_request( sub, tdata);
504 if (status != PJ_SUCCESS) {
505 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status);
506 return;
507 }
508
509 /* We're cheating here.
510 * We need to get a null terminated string from a pj_str_t.
511 * So grab the pointer from the hvalue and NULL terminate it, knowing
512 * that the NULL position will be occupied by a newline.
513 */
514 uri = refer_to->hvalue.ptr;
515 uri[refer_to->hvalue.slen] = '\0';
516
517 /* Now make the outgoing call. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000518 status = pjsua_make_call(existing_call->acc_index, uri, &new_call);
Benny Prijono26ff9062006-02-21 23:47:00 +0000519 if (status != PJ_SUCCESS) {
520
521 /* Notify xferer about the error */
522 status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
523 500, NULL, &tdata);
524 if (status != PJ_SUCCESS) {
525 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",
526 status);
527 return;
528 }
529 status = pjsip_xfer_send_request(sub, tdata);
530 if (status != PJ_SUCCESS) {
531 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",
532 status);
533 return;
534 }
535 return;
536 }
537
538 /* Put the server subscription in inv_data.
539 * Subsequent state changed in pjsua_inv_on_state_changed() will be
540 * reported back to the server subscription.
541 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000542 pjsua.calls[new_call].xfer_sub = sub;
Benny Prijono26ff9062006-02-21 23:47:00 +0000543
544 /* Put the invite_data in the subscription. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000545 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, &pjsua.calls[new_call]);
Benny Prijono26ff9062006-02-21 23:47:00 +0000546}
547
548
549/*
550 * This callback is called when transaction state has changed in INVITE
Benny Prijonob0808372006-03-02 21:18:58 +0000551 * session. We use this to trap:
552 * - incoming REFER request.
553 * - incoming MESSAGE request.
Benny Prijono26ff9062006-02-21 23:47:00 +0000554 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000555static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
556 pjsip_transaction *tsx,
557 pjsip_event *e)
Benny Prijono26ff9062006-02-21 23:47:00 +0000558{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000559 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
560
Benny Prijono26ff9062006-02-21 23:47:00 +0000561 if (tsx->role==PJSIP_ROLE_UAS &&
562 tsx->state==PJSIP_TSX_STATE_TRYING &&
563 pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0)
564 {
565 /*
566 * Incoming REFER request.
567 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000568 on_call_transfered(call->inv, e->body.tsx_state.src.rdata);
Benny Prijonob0808372006-03-02 21:18:58 +0000569
Benny Prijono26ff9062006-02-21 23:47:00 +0000570 }
Benny Prijonob0808372006-03-02 21:18:58 +0000571 else if (tsx->role==PJSIP_ROLE_UAS &&
572 tsx->state==PJSIP_TSX_STATE_TRYING &&
573 pjsip_method_cmp(&tsx->method, &pjsip_message_method)==0)
574 {
575 /*
576 * Incoming MESSAGE request!
577 */
578 pjsip_rx_data *rdata;
579 pjsip_msg *msg;
580 pjsip_accept_hdr *accept_hdr;
581 pj_status_t status;
582
583 rdata = e->body.tsx_state.src.rdata;
584 msg = rdata->msg_info.msg;
585
586 /* Request MUST have message body, with Content-Type equal to
587 * "text/plain".
588 */
589 if (pjsua_im_accept_pager(rdata, &accept_hdr) == PJ_FALSE) {
590
591 pjsip_hdr hdr_list;
592
593 pj_list_init(&hdr_list);
594 pj_list_push_back(&hdr_list, accept_hdr);
595
596 pjsip_dlg_respond( inv->dlg, rdata, PJSIP_SC_NOT_ACCEPTABLE_HERE,
597 NULL, &hdr_list, NULL );
598 return;
599 }
600
601 /* Respond with 200 first, so that remote doesn't retransmit in case
602 * the UI takes too long to process the message.
603 */
604 status = pjsip_dlg_respond( inv->dlg, rdata, 200, NULL, NULL, NULL);
605
606 /* Process MESSAGE request */
607 pjsua_im_process_pager(call->index, &inv->dlg->remote.info_str,
608 &inv->dlg->local.info_str, rdata);
609 }
610
Benny Prijono26ff9062006-02-21 23:47:00 +0000611}
612
613
614/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000615 * This callback is called by invite session framework when UAC session
616 * has forked.
617 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000618static void pjsua_call_on_forked( pjsip_inv_session *inv,
619 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000620{
621 PJ_UNUSED_ARG(inv);
622 PJ_UNUSED_ARG(e);
623
624 PJ_TODO(HANDLE_FORKED_DIALOG);
625}
626
627
628/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000629 * Create inactive SDP for call hold.
630 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000631static pj_status_t create_inactive_sdp(pjsua_call *call,
Benny Prijono26ff9062006-02-21 23:47:00 +0000632 pjmedia_sdp_session **p_answer)
633{
634 pj_status_t status;
635 pjmedia_sdp_conn *conn;
636 pjmedia_sdp_attr *attr;
637 pjmedia_sdp_session *sdp;
638
639 /* Create new offer */
640 status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000641 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +0000642 if (status != PJ_SUCCESS) {
643 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
644 return status;
645 }
646
647 /* Get SDP media connection line */
648 conn = sdp->media[0]->conn;
649 if (!conn)
650 conn = sdp->conn;
651
652 /* Modify address */
653 conn->addr = pj_str("0.0.0.0");
654
655 /* Remove existing directions attributes */
656 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
657 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
658 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
659 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
660
661 /* Add inactive attribute */
662 attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL);
663 pjmedia_sdp_media_add_attr(sdp->media[0], attr);
664
665 *p_answer = sdp;
666
667 return status;
668}
669
670/*
671 * Called when session received new offer.
672 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000673static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
674 const pjmedia_sdp_session *offer)
Benny Prijono26ff9062006-02-21 23:47:00 +0000675{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000676 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000677 pjmedia_sdp_conn *conn;
678 pjmedia_sdp_session *answer;
679 pj_bool_t is_remote_active;
680 pj_status_t status;
681
Benny Prijonoa91a0032006-02-26 21:23:45 +0000682 call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000683
684 /*
685 * See if remote is offering active media (i.e. not on-hold)
686 */
687 is_remote_active = PJ_TRUE;
688
689 conn = offer->media[0]->conn;
690 if (!conn)
691 conn = offer->conn;
692
693 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
694 pj_strcmp2(&conn->addr, "0")==0)
695 {
696 is_remote_active = PJ_FALSE;
697
698 }
699 else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))
700 {
701 is_remote_active = PJ_FALSE;
702 }
703
704 PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s",
705 (is_remote_active ? "active" : "inactive")));
706
707 /* Supply candidate answer */
708 if (is_remote_active) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000709 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
710 &call->skinfo, &answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000711 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000712 status = create_inactive_sdp( call, &answer );
Benny Prijono26ff9062006-02-21 23:47:00 +0000713 }
714
715 if (status != PJ_SUCCESS) {
716 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
717 return;
718 }
719
Benny Prijonoa91a0032006-02-26 21:23:45 +0000720 status = pjsip_inv_set_sdp_answer(call->inv, answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000721 if (status != PJ_SUCCESS) {
722 pjsua_perror(THIS_FILE, "Unable to set answer", status);
723 return;
724 }
725
726}
727
Benny Prijono1c2bf462006-03-05 11:54:02 +0000728/* Disconnect call */
729static void call_disconnect(pjsip_inv_session *inv,
730 int st_code)
731{
732 pjsip_tx_data *tdata;
733 pj_status_t status;
734
735 status = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
736 if (status == PJ_SUCCESS)
737 status = pjsip_inv_send_msg(inv, tdata, NULL);
738
739 if (status != PJ_SUCCESS) {
740 pjsua_perror(THIS_FILE, "Unable to disconnect call", status);
741 }
742}
Benny Prijono26ff9062006-02-21 23:47:00 +0000743
744/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000745 * Callback to be called when SDP offer/answer negotiation has just completed
746 * in the session. This function will start/update media if negotiation
747 * has succeeded.
748 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000749static void pjsua_call_on_media_update(pjsip_inv_session *inv,
750 pj_status_t status)
Benny Prijono84126ab2006-02-09 09:30:09 +0000751{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000752 pjsua_call *call;
Benny Prijono84126ab2006-02-09 09:30:09 +0000753 const pjmedia_sdp_session *local_sdp;
754 const pjmedia_sdp_session *remote_sdp;
Benny Prijono26ff9062006-02-21 23:47:00 +0000755 pjmedia_port *media_port;
756 pj_str_t port_name;
757 char tmp[PJSIP_MAX_URL_SIZE];
Benny Prijono84126ab2006-02-09 09:30:09 +0000758
Benny Prijonoa91a0032006-02-26 21:23:45 +0000759 call = inv->dlg->mod_data[pjsua.mod.id];
760
Benny Prijono84126ab2006-02-09 09:30:09 +0000761 if (status != PJ_SUCCESS) {
762
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000763 pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000764
765 /* Disconnect call if this is not a re-INVITE */
766 if (inv->state != PJSIP_INV_STATE_CONFIRMED) {
767 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
768 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000769 return;
770
771 }
772
773 /* Destroy existing media session, if any. */
774
Benny Prijonoa91a0032006-02-26 21:23:45 +0000775 if (call && call->session) {
776 pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
777 pjmedia_session_destroy(call->session);
778 call->session = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +0000779 }
780
781 /* Get local and remote SDP */
782
Benny Prijonoa91a0032006-02-26 21:23:45 +0000783 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000784 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000785 pjsua_perror(THIS_FILE,
786 "Unable to retrieve currently active local SDP",
787 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000788 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000789 return;
790 }
791
792
Benny Prijonoa91a0032006-02-26 21:23:45 +0000793 status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000794 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000795 pjsua_perror(THIS_FILE,
796 "Unable to retrieve currently active remote SDP",
797 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000798 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000799 return;
800 }
801
Benny Prijono84126ab2006-02-09 09:30:09 +0000802 /* Create new media session.
803 * The media session is active immediately.
804 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000805 if (pjsua.null_audio)
806 return;
807
808 status = pjmedia_session_create( pjsua.med_endpt, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000809 &call->skinfo,
Benny Prijono26ff9062006-02-21 23:47:00 +0000810 local_sdp, remote_sdp,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000811 call,
812 &call->session );
Benny Prijono26ff9062006-02-21 23:47:00 +0000813 if (status != PJ_SUCCESS) {
814 pjsua_perror(THIS_FILE, "Unable to create media session",
815 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000816 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono26ff9062006-02-21 23:47:00 +0000817 return;
Benny Prijono84126ab2006-02-09 09:30:09 +0000818 }
Benny Prijono26ff9062006-02-21 23:47:00 +0000819
820
821 /* Get the port interface of the first stream in the session.
822 * We need the port interface to add to the conference bridge.
823 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000824 pjmedia_session_get_port(call->session, 0, &media_port);
Benny Prijono26ff9062006-02-21 23:47:00 +0000825
826
827 /*
828 * Add the call to conference bridge.
829 */
830 port_name.ptr = tmp;
831 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000832 call->inv->dlg->remote.info->uri,
Benny Prijono26ff9062006-02-21 23:47:00 +0000833 tmp, sizeof(tmp));
834 if (port_name.slen < 1) {
835 port_name = pj_str("call");
836 }
Benny Prijonoa91a0032006-02-26 21:23:45 +0000837 status = pjmedia_conf_add_port( pjsua.mconf, call->inv->pool,
Benny Prijono26ff9062006-02-21 23:47:00 +0000838 media_port,
839 &port_name,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000840 &call->conf_slot);
Benny Prijono26ff9062006-02-21 23:47:00 +0000841 if (status != PJ_SUCCESS) {
842 pjsua_perror(THIS_FILE, "Unable to create conference slot",
843 status);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000844 pjmedia_session_destroy(call->session);
845 call->session = NULL;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000846 call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR);
Benny Prijono26ff9062006-02-21 23:47:00 +0000847 return;
848 }
849
Benny Prijono64f851e2006-02-23 13:49:28 +0000850 /* If auto-play is configured, connect the call to the file player
851 * port
Benny Prijono26ff9062006-02-21 23:47:00 +0000852 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000853 if (pjsua.auto_play && pjsua.wav_file &&
854 call->inv->role == PJSIP_ROLE_UAS)
855 {
Benny Prijono64f851e2006-02-23 13:49:28 +0000856
857 pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000858 call->conf_slot);
859
860 } else if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) {
861
862 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
863 call->conf_slot);
864
865 } else if (pjsua.auto_conf) {
866
867 int i;
868
869 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot);
870 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0);
871
872 for (i=0; i < pjsua.max_calls; ++i) {
873
874 if (!pjsua.calls[i].session)
875 continue;
876
877 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
878 pjsua.calls[i].conf_slot);
879 pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot,
880 call->conf_slot);
881 }
Benny Prijono64f851e2006-02-23 13:49:28 +0000882
883 } else {
884
885 /* Connect new call to the sound device port (port zero) in the
886 * main conference bridge.
887 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000888 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot);
889 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0);
Benny Prijono64f851e2006-02-23 13:49:28 +0000890 }
891
Benny Prijono26ff9062006-02-21 23:47:00 +0000892
893 /* Done. */
894 {
895 struct pjmedia_session_info sess_info;
896 char info[80];
897 int info_len = 0;
898 unsigned i;
899
Benny Prijonoa91a0032006-02-26 21:23:45 +0000900 pjmedia_session_get_info(call->session, &sess_info);
Benny Prijono26ff9062006-02-21 23:47:00 +0000901 for (i=0; i<sess_info.stream_cnt; ++i) {
902 int len;
903 const char *dir;
904 pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
905
906 switch (strm_info->dir) {
907 case PJMEDIA_DIR_NONE:
908 dir = "inactive";
909 break;
910 case PJMEDIA_DIR_ENCODING:
911 dir = "sendonly";
912 break;
913 case PJMEDIA_DIR_DECODING:
914 dir = "recvonly";
915 break;
916 case PJMEDIA_DIR_ENCODING_DECODING:
917 dir = "sendrecv";
918 break;
919 default:
920 dir = "unknown";
921 break;
922 }
923 len = pj_ansi_sprintf( info+info_len,
924 ", stream #%d: %.*s (%s)", i,
925 (int)strm_info->fmt.encoding_name.slen,
Benny Prijonoab7399b2006-02-27 00:40:31 +0000926 strm_info->fmt.encoding_name.ptr,
Benny Prijono26ff9062006-02-21 23:47:00 +0000927 dir);
928 if (len > 0)
929 info_len += len;
930 }
931 PJ_LOG(3,(THIS_FILE,"Media started%s", info));
932 }
933}
934
935
936/*
937 * Hangup call.
938 */
Benny Prijono1c2bf462006-03-05 11:54:02 +0000939void pjsua_call_hangup(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +0000940{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000941 pjsua_call *call;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000942 int code;
Benny Prijono26ff9062006-02-21 23:47:00 +0000943 pj_status_t status;
944 pjsip_tx_data *tdata;
945
Benny Prijonoa91a0032006-02-26 21:23:45 +0000946
947 call = &pjsua.calls[call_index];
948
949 if (!call->inv) {
950 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
951 return;
952 }
953
Benny Prijono1c2bf462006-03-05 11:54:02 +0000954 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
955 code = PJSIP_SC_OK;
956 else if (call->inv->role == PJSIP_ROLE_UAS)
957 code = PJSIP_SC_DECLINE;
958 else
959 code = PJSIP_SC_REQUEST_TERMINATED;
960
Benny Prijonoa91a0032006-02-26 21:23:45 +0000961 status = pjsip_inv_end_session(call->inv, code, NULL, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +0000962 if (status != PJ_SUCCESS) {
963 pjsua_perror(THIS_FILE,
964 "Failed to create end session message",
965 status);
966 return;
967 }
968
Benny Prijonofccab712006-02-22 22:23:22 +0000969 /* pjsip_inv_end_session may return PJ_SUCCESS with NULL
970 * as p_tdata when INVITE transaction has not been answered
971 * with any provisional responses.
972 */
973 if (tdata == NULL)
974 return;
975
Benny Prijonoa91a0032006-02-26 21:23:45 +0000976 status = pjsip_inv_send_msg(call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000977 if (status != PJ_SUCCESS) {
978 pjsua_perror(THIS_FILE,
979 "Failed to send end session message",
980 status);
981 return;
982 }
983}
984
985
986/*
987 * Put call on-Hold.
988 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000989void pjsua_call_set_hold(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +0000990{
991 pjmedia_sdp_session *sdp;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000992 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000993 pjsip_tx_data *tdata;
994 pj_status_t status;
995
Benny Prijonoa91a0032006-02-26 21:23:45 +0000996 call = &pjsua.calls[call_index];
997
998 if (!call->inv) {
999 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1000 return;
1001 }
1002
1003 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001004 PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
1005 return;
1006 }
1007
Benny Prijonoa91a0032006-02-26 21:23:45 +00001008 status = create_inactive_sdp(call, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001009 if (status != PJ_SUCCESS)
1010 return;
1011
1012 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001013 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001014 if (status != PJ_SUCCESS) {
1015 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1016 return;
1017 }
1018
Benny Prijonoa91a0032006-02-26 21:23:45 +00001019 status = pjsip_inv_send_msg( call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +00001020 if (status != PJ_SUCCESS) {
1021 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1022 return;
1023 }
1024}
1025
1026
1027/*
1028 * re-INVITE.
1029 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001030void pjsua_call_reinvite(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001031{
1032 pjmedia_sdp_session *sdp;
1033 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001034 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001035 pj_status_t status;
1036
Benny Prijonoa91a0032006-02-26 21:23:45 +00001037 call = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +00001038
Benny Prijonoa91a0032006-02-26 21:23:45 +00001039 if (!call->inv) {
1040 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1041 return;
1042 }
1043
1044
1045 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001046 PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
1047 return;
1048 }
1049
1050 /* Create SDP */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001051 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
1052 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001053 if (status != PJ_SUCCESS) {
Benny Prijonoa91a0032006-02-26 21:23:45 +00001054 pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",
1055 status);
Benny Prijono26ff9062006-02-21 23:47:00 +00001056 return;
1057 }
1058
1059 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001060 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001061 if (status != PJ_SUCCESS) {
1062 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1063 return;
1064 }
1065
Benny Prijonoa91a0032006-02-26 21:23:45 +00001066 status = pjsip_inv_send_msg( call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +00001067 if (status != PJ_SUCCESS) {
1068 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1069 return;
1070 }
1071}
1072
1073
1074/*
1075 * Transfer call.
1076 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001077void pjsua_call_xfer(int call_index, const char *dest)
Benny Prijono26ff9062006-02-21 23:47:00 +00001078{
1079 pjsip_evsub *sub;
1080 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001081 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001082 pj_str_t tmp;
1083 pj_status_t status;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001084
Benny Prijono26ff9062006-02-21 23:47:00 +00001085
Benny Prijonoa91a0032006-02-26 21:23:45 +00001086 call = &pjsua.calls[call_index];
1087
1088 if (!call->inv) {
1089 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1090 return;
1091 }
1092
Benny Prijono26ff9062006-02-21 23:47:00 +00001093 /* Create xfer client subscription.
1094 * We're not interested in knowing the transfer result, so we
1095 * put NULL as the callback.
1096 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001097 status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub);
Benny Prijono26ff9062006-02-21 23:47:00 +00001098 if (status != PJ_SUCCESS) {
1099 pjsua_perror(THIS_FILE, "Unable to create xfer", status);
1100 return;
1101 }
1102
1103 /*
1104 * Create REFER request.
1105 */
1106 status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
1107 if (status != PJ_SUCCESS) {
1108 pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
1109 return;
1110 }
1111
1112 /* Send. */
1113 status = pjsip_xfer_send_request(sub, tdata);
1114 if (status != PJ_SUCCESS) {
1115 pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
1116 return;
1117 }
1118
1119 /* For simplicity (that's what this program is intended to be!),
1120 * leave the original invite session as it is. More advanced application
1121 * may want to hold the INVITE, or terminate the invite, or whatever.
1122 */
Benny Prijono84126ab2006-02-09 09:30:09 +00001123}
Benny Prijono834aee32006-02-19 01:38:06 +00001124
1125
Benny Prijonob0808372006-03-02 21:18:58 +00001126/**
1127 * Send instant messaging inside INVITE session.
1128 */
1129void pjsua_call_send_im(int call_index, const char *str)
1130{
1131 pjsua_call *call;
1132 const pj_str_t mime_text = pj_str("text");
1133 const pj_str_t mime_plain = pj_str("plain");
1134 pj_str_t text;
1135 pjsip_tx_data *tdata;
1136 pj_status_t status;
1137
1138 call = &pjsua.calls[call_index];
1139
1140 if (!call->inv) {
1141 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1142 return;
1143 }
1144
1145 /* Lock dialog. */
1146 pjsip_dlg_inc_lock(call->inv->dlg);
1147
1148 /* Create request message. */
1149 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1150 -1, &tdata);
1151 if (status != PJ_SUCCESS) {
1152 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1153 goto on_return;
1154 }
1155
1156 /* Add accept header. */
1157 pjsip_msg_add_hdr( tdata->msg,
1158 (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
1159
1160 /* Create "text/plain" message body. */
1161 tdata->msg->body = pjsip_msg_body_create( tdata->pool, &mime_text,
1162 &mime_plain,
1163 pj_cstr(&text, str));
1164 if (tdata->msg->body == NULL) {
1165 pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM);
1166 pjsip_tx_data_dec_ref(tdata);
1167 goto on_return;
1168 }
1169
1170 /* Send the request. */
1171 status = pjsip_dlg_send_request( call->inv->dlg, tdata, NULL);
1172 if (status != PJ_SUCCESS) {
1173 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1174 goto on_return;
1175 }
1176
1177on_return:
1178 pjsip_dlg_dec_lock(call->inv->dlg);
1179}
1180
1181
1182/**
1183 * Send IM typing indication inside INVITE session.
1184 */
1185void pjsua_call_typing(int call_index, pj_bool_t is_typing)
1186{
1187 pjsua_call *call;
1188 pjsip_tx_data *tdata;
1189 pj_status_t status;
1190
1191 call = &pjsua.calls[call_index];
1192
1193 if (!call->inv) {
1194 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1195 return;
1196 }
1197
1198 /* Lock dialog. */
1199 pjsip_dlg_inc_lock(call->inv->dlg);
1200
1201 /* Create request message. */
1202 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1203 -1, &tdata);
1204 if (status != PJ_SUCCESS) {
1205 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1206 goto on_return;
1207 }
1208
1209 /* Create "application/im-iscomposing+xml" msg body. */
1210 tdata->msg->body = pjsip_iscomposing_create_body(tdata->pool, is_typing,
1211 NULL, NULL, -1);
1212
1213 /* Send the request. */
1214 status = pjsip_dlg_send_request( call->inv->dlg, tdata, NULL);
1215 if (status != PJ_SUCCESS) {
1216 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1217 goto on_return;
1218 }
1219
1220on_return:
1221 pjsip_dlg_dec_lock(call->inv->dlg);}
1222
1223
Benny Prijono834aee32006-02-19 01:38:06 +00001224/*
1225 * Terminate all calls.
1226 */
Benny Prijono1c2bf462006-03-05 11:54:02 +00001227void pjsua_call_hangup_all(void)
Benny Prijono834aee32006-02-19 01:38:06 +00001228{
Benny Prijonoa91a0032006-02-26 21:23:45 +00001229 int i;
Benny Prijono834aee32006-02-19 01:38:06 +00001230
Benny Prijonoa91a0032006-02-26 21:23:45 +00001231 for (i=0; i<pjsua.max_calls; ++i) {
Benny Prijono834aee32006-02-19 01:38:06 +00001232 pjsip_tx_data *tdata;
Benny Prijono1c2bf462006-03-05 11:54:02 +00001233 int st_code;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001234 pjsua_call *call;
Benny Prijono834aee32006-02-19 01:38:06 +00001235
Benny Prijonoa91a0032006-02-26 21:23:45 +00001236 if (pjsua.calls[i].inv == NULL)
1237 continue;
Benny Prijono834aee32006-02-19 01:38:06 +00001238
Benny Prijonoa91a0032006-02-26 21:23:45 +00001239 call = &pjsua.calls[i];
1240
Benny Prijono1c2bf462006-03-05 11:54:02 +00001241 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
1242 st_code = 200;
1243 } else {
1244 st_code = PJSIP_SC_GONE;
1245 }
1246
1247 if (pjsip_inv_end_session(call->inv, st_code, NULL, &tdata)==0) {
Benny Prijonofccab712006-02-22 22:23:22 +00001248 if (tdata)
Benny Prijonoa91a0032006-02-26 21:23:45 +00001249 pjsip_inv_send_msg(call->inv, tdata, NULL);
Benny Prijonofccab712006-02-22 22:23:22 +00001250 }
Benny Prijono834aee32006-02-19 01:38:06 +00001251 }
1252}
1253
Benny Prijono26ff9062006-02-21 23:47:00 +00001254
Benny Prijonoa91a0032006-02-26 21:23:45 +00001255pj_status_t pjsua_call_init(void)
1256{
1257 /* Initialize invite session callback. */
1258 pjsip_inv_callback inv_cb;
1259 pj_status_t status;
1260
1261 pj_memset(&inv_cb, 0, sizeof(inv_cb));
1262 inv_cb.on_state_changed = &pjsua_call_on_state_changed;
1263 inv_cb.on_new_session = &pjsua_call_on_forked;
1264 inv_cb.on_media_update = &pjsua_call_on_media_update;
1265 inv_cb.on_rx_offer = &pjsua_call_on_rx_offer;
1266 inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed;
1267
1268
1269 /* Initialize invite session module: */
1270 status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb);
1271
1272 return status;
1273}