blob: 16823e4d99a67ec3aa43a0ca8af30c86fda27535 [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
Benny Prijono105217f2006-03-06 16:25:59 +000032#define REFRESH_CALL_TIMER 0x63
33#define HANGUP_CALL_TIMER 0x64
34
35/* Proto */
36static void schedule_call_timer( pjsua_call *call, pj_timer_entry *e,
37 int timer_type, int duration );
38
39/*
40 * Timer callback when UAS needs to send re-INVITE to see if remote
41 * is still there.
42 */
43static void call_on_timer(pj_timer_heap_t *ht, pj_timer_entry *e)
44{
45 pjsua_call *call = e->user_data;
46
47 PJ_UNUSED_ARG(ht);
48
49 if (e->id == REFRESH_CALL_TIMER) {
50
51 /* If call is still not connected, hangup. */
52 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
53 PJ_LOG(3,(THIS_FILE, "Refresh call timer is called when "
54 "invite is still not confirmed. Call %d will "
55 "disconnect.", call->index));
56 pjsua_call_hangup(call->index);
57 } else {
58 PJ_LOG(3,(THIS_FILE, "Refreshing call %d", call->index));
59 schedule_call_timer(call,e,REFRESH_CALL_TIMER,pjsua.uas_refresh);
60 pjsua_call_reinvite(call->index);
61 }
62
63 } else if (e->id == HANGUP_CALL_TIMER) {
64 PJ_LOG(3,(THIS_FILE, "Call %d duration exceeded, disconnecting call",
65 call->index));
66 pjsua_call_hangup(call->index);
67
68 }
69}
70
71/*
72 * Schedule call timer.
73 */
74static void schedule_call_timer( pjsua_call *call, pj_timer_entry *e,
75 int timer_type, int duration )
76{
77 pj_time_val timeout;
78
79 if (duration == 0) {
80 /* Cancel timer. */
81 if (e->id != 0) {
82 pjsip_endpt_cancel_timer(pjsua.endpt, e);
83 e->id = 0;
84 }
85
86 } else {
87 /* Schedule timer. */
88 timeout.sec = duration;
89 timeout.msec = 0;
90
91 e->cb = &call_on_timer;
92 e->id = timer_type;
93 e->user_data = call;
94
95 pjsip_endpt_schedule_timer( pjsua.endpt, e, &timeout);
96 }
97}
98
99
Benny Prijono84126ab2006-02-09 09:30:09 +0000100/**
101 * Make outgoing call.
102 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000103pj_status_t pjsua_make_call(int acc_index,
104 const char *cstr_dest_uri,
105 int *p_call_index)
Benny Prijono84126ab2006-02-09 09:30:09 +0000106{
107 pj_str_t dest_uri;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000108 pjsip_dialog *dlg = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +0000109 pjmedia_sdp_session *offer;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000110 pjsip_inv_session *inv = NULL;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000111 int call_index = -1;
Benny Prijono84126ab2006-02-09 09:30:09 +0000112 pjsip_tx_data *tdata;
113 pj_status_t status;
114
115 /* Convert cstr_dest_uri to dest_uri */
116
117 dest_uri = pj_str((char*)cstr_dest_uri);
118
Benny Prijonoa91a0032006-02-26 21:23:45 +0000119 /* Find free call slot. */
120 for (call_index=0; call_index<pjsua.max_calls; ++call_index) {
121 if (pjsua.calls[call_index].inv == NULL)
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000122 break;
123 }
124
Benny Prijonoa91a0032006-02-26 21:23:45 +0000125 if (call_index == pjsua.max_calls) {
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000126 PJ_LOG(3,(THIS_FILE, "Error: too many calls!"));
127 return PJ_ETOOMANY;
128 }
129
Benny Prijono84126ab2006-02-09 09:30:09 +0000130 /* Create outgoing dialog: */
131
Benny Prijonoa91a0032006-02-26 21:23:45 +0000132 status = pjsip_dlg_create_uac( pjsip_ua_instance(),
133 &pjsua.acc[acc_index].local_uri,
134 &pjsua.acc[acc_index].contact_uri,
135 &dest_uri, &dest_uri,
Benny Prijono84126ab2006-02-09 09:30:09 +0000136 &dlg);
137 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000138 pjsua_perror(THIS_FILE, "Dialog creation failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000139 return status;
140 }
141
142 /* Get media capability from media endpoint: */
143
Benny Prijonoa91a0032006-02-26 21:23:45 +0000144 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 1,
145 &pjsua.calls[call_index].skinfo,
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000146 &offer);
Benny Prijono84126ab2006-02-09 09:30:09 +0000147 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000148 pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000149 goto on_error;
150 }
151
152 /* Create the INVITE session: */
153
154 status = pjsip_inv_create_uac( dlg, offer, 0, &inv);
155 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000156 pjsua_perror(THIS_FILE, "Invite session creation failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000157 goto on_error;
158 }
159
160
161 /* Create and associate our data in the session. */
162
Benny Prijonoa91a0032006-02-26 21:23:45 +0000163 pjsua.calls[call_index].inv = inv;
164
165 dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
166 inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
Benny Prijono84126ab2006-02-09 09:30:09 +0000167
168
169 /* Set dialog Route-Set: */
170
Benny Prijonoa91a0032006-02-26 21:23:45 +0000171 if (!pj_list_empty(&pjsua.acc[acc_index].route_set))
172 pjsip_dlg_set_route_set(dlg, &pjsua.acc[acc_index].route_set);
Benny Prijono84126ab2006-02-09 09:30:09 +0000173
174
175 /* Set credentials: */
176
177 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,
178 pjsua.cred_info);
179
180
181 /* Create initial INVITE: */
182
183 status = pjsip_inv_invite(inv, &tdata);
184 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000185 pjsua_perror(THIS_FILE, "Unable to create initial INVITE request",
186 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000187 goto on_error;
188 }
189
190
191 /* Send initial INVITE: */
192
193 status = pjsip_inv_send_msg(inv, tdata, NULL);
194 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000195 pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",
196 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000197 goto on_error;
198 }
199
200
201 /* Done. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000202
203 ++pjsua.call_cnt;
204
205 if (p_call_index)
206 *p_call_index = call_index;
Benny Prijono84126ab2006-02-09 09:30:09 +0000207
208 return PJ_SUCCESS;
209
210
211on_error:
Benny Prijono1c2bf462006-03-05 11:54:02 +0000212 if (inv != NULL) {
213 pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE);
214 } else {
215 pjsip_dlg_terminate(dlg);
216 }
217
Benny Prijonoa91a0032006-02-26 21:23:45 +0000218 if (call_index != -1) {
219 pjsua.calls[call_index].inv = NULL;
220 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000221 return status;
222}
223
224
225/**
226 * Handle incoming INVITE request.
227 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000228pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
Benny Prijono84126ab2006-02-09 09:30:09 +0000229{
230 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
231 pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
232 pjsip_msg *msg = rdata->msg_info.msg;
Benny Prijono26ff9062006-02-21 23:47:00 +0000233 pjsip_tx_data *response = NULL;
234 unsigned options = 0;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000235 pjsip_inv_session *inv = NULL;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000236 int acc_index;
237 int call_index = -1;
Benny Prijono26ff9062006-02-21 23:47:00 +0000238 pjmedia_sdp_session *answer;
Benny Prijono26ff9062006-02-21 23:47:00 +0000239 pj_status_t status;
Benny Prijono84126ab2006-02-09 09:30:09 +0000240
Benny Prijono26ff9062006-02-21 23:47:00 +0000241 /* Don't want to handle anything but INVITE */
242 if (msg->line.req.method.id != PJSIP_INVITE_METHOD)
243 return PJ_FALSE;
244
245 /* Don't want to handle anything that's already associated with
246 * existing dialog or transaction.
Benny Prijono84126ab2006-02-09 09:30:09 +0000247 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000248 if (dlg || tsx)
249 return PJ_FALSE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000250
Benny Prijono84126ab2006-02-09 09:30:09 +0000251
Benny Prijono26ff9062006-02-21 23:47:00 +0000252 /* Verify that we can handle the request. */
253 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
254 pjsua.endpt, &response);
255 if (status != PJ_SUCCESS) {
Benny Prijono84126ab2006-02-09 09:30:09 +0000256
Benny Prijono26ff9062006-02-21 23:47:00 +0000257 /*
258 * No we can't handle the incoming INVITE request.
259 */
Benny Prijono84126ab2006-02-09 09:30:09 +0000260
Benny Prijono26ff9062006-02-21 23:47:00 +0000261 if (response) {
262 pjsip_response_addr res_addr;
Benny Prijono84126ab2006-02-09 09:30:09 +0000263
Benny Prijono26ff9062006-02-21 23:47:00 +0000264 pjsip_get_response_addr(response->pool, rdata, &res_addr);
265 pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,
266 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000267
268 } else {
Benny Prijono84126ab2006-02-09 09:30:09 +0000269
Benny Prijono26ff9062006-02-21 23:47:00 +0000270 /* Respond with 500 (Internal Server Error) */
271 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
272 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000273 }
274
Benny Prijono26ff9062006-02-21 23:47:00 +0000275 return PJ_TRUE;
276 }
277
278
279 /*
280 * Yes we can handle the incoming INVITE request.
281 */
282
283 /* Find free call slot. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000284 for (call_index=0; call_index < pjsua.max_calls; ++call_index) {
285 if (pjsua.calls[call_index].inv == NULL)
Benny Prijono26ff9062006-02-21 23:47:00 +0000286 break;
287 }
288
Benny Prijonoa91a0032006-02-26 21:23:45 +0000289 if (call_index == PJSUA_MAX_CALLS) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000290 pjsip_endpt_respond_stateless(pjsua.endpt, rdata,
291 PJSIP_SC_BUSY_HERE, NULL,
292 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000293 return PJ_TRUE;
294 }
295
Benny Prijono26ff9062006-02-21 23:47:00 +0000296
Benny Prijono26ff9062006-02-21 23:47:00 +0000297 /* Get media capability from media endpoint: */
298
Benny Prijonoa91a0032006-02-26 21:23:45 +0000299 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 1,
300 &pjsua.calls[call_index].skinfo,
Benny Prijono26ff9062006-02-21 23:47:00 +0000301 &answer );
302 if (status != PJ_SUCCESS) {
303 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
304 NULL, NULL);
305
Benny Prijono26ff9062006-02-21 23:47:00 +0000306 return PJ_TRUE;
307 }
308
Benny Prijonoa91a0032006-02-26 21:23:45 +0000309 /* TODO:
310 *
311 * Get which account is most likely to be associated with this incoming
312 * call. We need the account to find which contact URI to put for
313 * the call.
314 */
315 acc_index = 0;
316
Benny Prijono26ff9062006-02-21 23:47:00 +0000317 /* Create dialog: */
318
319 status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000320 &pjsua.acc[acc_index].contact_uri,
321 &dlg);
Benny Prijono26ff9062006-02-21 23:47:00 +0000322 if (status != PJ_SUCCESS) {
323 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
324 NULL, NULL);
325
Benny Prijono26ff9062006-02-21 23:47:00 +0000326 return PJ_TRUE;
327 }
328
329
330 /* Create invite session: */
331
332 status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
333 if (status != PJ_SUCCESS) {
334
Benny Prijonob0808372006-03-02 21:18:58 +0000335 pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000336 pjsip_dlg_terminate(dlg);
Benny Prijono26ff9062006-02-21 23:47:00 +0000337 return PJ_TRUE;
338 }
339
340
341 /* Create and attach pjsua data to the dialog: */
342
Benny Prijonoa91a0032006-02-26 21:23:45 +0000343 pjsua.calls[call_index].inv = inv;
Benny Prijono26ff9062006-02-21 23:47:00 +0000344
Benny Prijonoa91a0032006-02-26 21:23:45 +0000345 dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
346 inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +0000347
348
Benny Prijono64f851e2006-02-23 13:49:28 +0000349 /* Must answer with some response to initial INVITE.
350 * If auto-answer flag is set, send 200 straight away, otherwise send 100.
351 */
352
353 status = pjsip_inv_initial_answer(inv, rdata,
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000354 (pjsua.auto_answer ? pjsua.auto_answer
355 : 100),
Benny Prijono64f851e2006-02-23 13:49:28 +0000356 NULL, NULL, &response);
Benny Prijono26ff9062006-02-21 23:47:00 +0000357 if (status != PJ_SUCCESS) {
358
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000359 int st_code;
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000360
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000361 pjsua_perror(THIS_FILE, "Unable to send answer to incoming INVITE",
362 status);
363
364 /* If failed to send 2xx response, there's a good chance that it is
365 * because SDP negotiation has failed.
366 */
367 if (pjsua.auto_answer/100 == 2)
368 st_code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
369 else
370 st_code = 500;
371
372 pjsip_dlg_respond(dlg, rdata, st_code, NULL, NULL, NULL);
373 pjsip_inv_terminate(inv, st_code, PJ_FALSE);
374 return PJ_TRUE;
Benny Prijono26ff9062006-02-21 23:47:00 +0000375
376 } else {
Benny Prijono64f851e2006-02-23 13:49:28 +0000377 status = pjsip_inv_send_msg(inv, response, NULL);
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000378 if (status != PJ_SUCCESS)
379 pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
Benny Prijono26ff9062006-02-21 23:47:00 +0000380 }
381
Benny Prijono64f851e2006-02-23 13:49:28 +0000382 if (pjsua.auto_answer < 200) {
383 PJ_LOG(3,(THIS_FILE,
384 "\nIncoming call!!\n"
385 "From: %.*s\n"
386 "To: %.*s\n"
387 "(press 'a' to answer, 'h' to decline)",
388 (int)dlg->remote.info_str.slen,
389 dlg->remote.info_str.ptr,
390 (int)dlg->local.info_str.slen,
391 dlg->local.info_str.ptr));
392 } else {
393 PJ_LOG(3,(THIS_FILE,
394 "Call From:%.*s To:%.*s was answered with %d (%s)",
395 (int)dlg->remote.info_str.slen,
396 dlg->remote.info_str.ptr,
397 (int)dlg->local.info_str.slen,
398 dlg->local.info_str.ptr,
399 pjsua.auto_answer,
400 pjsip_get_status_text(pjsua.auto_answer)->ptr ));
401 }
402
Benny Prijonoa91a0032006-02-26 21:23:45 +0000403 ++pjsua.call_cnt;
404
Benny Prijono105217f2006-03-06 16:25:59 +0000405 /* Schedule timer to refresh. */
406 if (pjsua.uas_refresh > 0) {
407 schedule_call_timer( &pjsua.calls[call_index],
408 &pjsua.calls[call_index].refresh_tm,
409 REFRESH_CALL_TIMER,
410 pjsua.uas_refresh);
411 }
412
413 /* Schedule timer to hangup call. */
414 if (pjsua.uas_duration > 0) {
415 schedule_call_timer( &pjsua.calls[call_index],
416 &pjsua.calls[call_index].hangup_tm,
417 HANGUP_CALL_TIMER,
418 pjsua.uas_duration);
419 }
420
Benny Prijono26ff9062006-02-21 23:47:00 +0000421 /* This INVITE request has been handled. */
422 return PJ_TRUE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000423}
424
425
426/*
427 * This callback receives notification from invite session when the
428 * session state has changed.
429 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000430static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
431 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000432{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000433 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000434
435 /* If this is an outgoing INVITE that was created because of
436 * REFER/transfer, send NOTIFY to transferer.
437 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000438 if (call && call->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000439 int st_code = -1;
440 pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
441
442
Benny Prijonoa91a0032006-02-26 21:23:45 +0000443 switch (call->inv->state) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000444 case PJSIP_INV_STATE_NULL:
445 case PJSIP_INV_STATE_CALLING:
446 /* Do nothing */
447 break;
448
449 case PJSIP_INV_STATE_EARLY:
450 case PJSIP_INV_STATE_CONNECTING:
451 st_code = e->body.tsx_state.tsx->status_code;
452 ev_state = PJSIP_EVSUB_STATE_ACTIVE;
453 break;
454
455 case PJSIP_INV_STATE_CONFIRMED:
456 /* When state is confirmed, send the final 200/OK and terminate
457 * subscription.
458 */
459 st_code = e->body.tsx_state.tsx->status_code;
460 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
461 break;
462
463 case PJSIP_INV_STATE_DISCONNECTED:
464 st_code = e->body.tsx_state.tsx->status_code;
465 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
466 break;
467 }
468
469 if (st_code != -1) {
470 pjsip_tx_data *tdata;
471 pj_status_t status;
472
Benny Prijonoa91a0032006-02-26 21:23:45 +0000473 status = pjsip_xfer_notify( call->xfer_sub,
Benny Prijono26ff9062006-02-21 23:47:00 +0000474 ev_state, st_code,
475 NULL, &tdata);
476 if (status != PJ_SUCCESS) {
477 pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);
478 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000479 status = pjsip_xfer_send_request(call->xfer_sub, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +0000480 if (status != PJ_SUCCESS) {
481 pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);
482 }
483 }
484 }
485 }
486
Benny Prijono84126ab2006-02-09 09:30:09 +0000487
Benny Prijonob0808372006-03-02 21:18:58 +0000488 pjsua_ui_on_call_state(call->index, e);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000489
490 /* call->inv may be NULL now */
491
Benny Prijono84126ab2006-02-09 09:30:09 +0000492 /* Destroy media session when invite session is disconnected. */
493 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono632ce712006-02-09 14:01:40 +0000494
Benny Prijonoa91a0032006-02-26 21:23:45 +0000495 pj_assert(call != NULL);
Benny Prijono632ce712006-02-09 14:01:40 +0000496
Benny Prijonoa91a0032006-02-26 21:23:45 +0000497 if (call && call->session) {
498 pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
499 pjmedia_session_destroy(call->session);
500 call->session = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +0000501
502 PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
503 }
504
Benny Prijono105217f2006-03-06 16:25:59 +0000505 /* Remove timers. */
506 schedule_call_timer(call, &call->refresh_tm, REFRESH_CALL_TIMER, 0);
507 schedule_call_timer(call, &call->hangup_tm, HANGUP_CALL_TIMER, 0);
508
509 /* Free call */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000510 call->inv = NULL;
511 --pjsua.call_cnt;
Benny Prijono84126ab2006-02-09 09:30:09 +0000512 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000513}
514
515
516/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000517 * Callback called by event framework when the xfer subscription state
518 * has changed.
519 */
520static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
521{
522
523 PJ_UNUSED_ARG(event);
524
525 /*
526 * We're only interested when subscription is terminated, to
527 * clear the xfer_sub member of the inv_data.
528 */
529 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000530 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000531
Benny Prijonoa91a0032006-02-26 21:23:45 +0000532 call = pjsip_evsub_get_mod_data(sub, pjsua.mod.id);
533 if (!call)
Benny Prijono26ff9062006-02-21 23:47:00 +0000534 return;
535
536 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000537 call->xfer_sub = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +0000538
539 PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated"));
540 }
541}
542
543
544/*
545 * Follow transfer (REFER) request.
546 */
547static void on_call_transfered( pjsip_inv_session *inv,
548 pjsip_rx_data *rdata )
549{
550 pj_status_t status;
551 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000552 pjsua_call *existing_call;
553 int new_call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000554 const pj_str_t str_refer_to = { "Refer-To", 8};
555 pjsip_generic_string_hdr *refer_to;
556 char *uri;
557 struct pjsip_evsub_user xfer_cb;
558 pjsip_evsub *sub;
559
Benny Prijonoa91a0032006-02-26 21:23:45 +0000560 existing_call = inv->dlg->mod_data[pjsua.mod.id];
561
Benny Prijono26ff9062006-02-21 23:47:00 +0000562 /* Find the Refer-To header */
563 refer_to = (pjsip_generic_string_hdr*)
564 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
565
566 if (refer_to == NULL) {
567 /* Invalid Request.
568 * No Refer-To header!
569 */
570 PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!"));
Benny Prijonob0808372006-03-02 21:18:58 +0000571 pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000572 return;
573 }
574
575 PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s",
576 (int)inv->dlg->remote.info_str.slen,
577 inv->dlg->remote.info_str.ptr,
578 (int)refer_to->hvalue.slen,
579 refer_to->hvalue.ptr));
580
581 /* Init callback */
582 pj_memset(&xfer_cb, 0, sizeof(xfer_cb));
583 xfer_cb.on_evsub_state = &xfer_on_evsub_state;
584
585 /* Create transferee event subscription */
586 status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
587 if (status != PJ_SUCCESS) {
588 pjsua_perror(THIS_FILE, "Unable to create xfer uas", status);
Benny Prijonob0808372006-03-02 21:18:58 +0000589 pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000590 return;
591 }
592
593 /* Accept the REFER request, send 200 (OK). */
594 pjsip_xfer_accept(sub, rdata, 200, NULL);
595
596 /* Create initial NOTIFY request */
597 status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
598 100, NULL, &tdata);
599 if (status != PJ_SUCCESS) {
600 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status);
601 return;
602 }
603
604 /* Send initial NOTIFY request */
605 status = pjsip_xfer_send_request( sub, tdata);
606 if (status != PJ_SUCCESS) {
607 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status);
608 return;
609 }
610
611 /* We're cheating here.
612 * We need to get a null terminated string from a pj_str_t.
613 * So grab the pointer from the hvalue and NULL terminate it, knowing
614 * that the NULL position will be occupied by a newline.
615 */
616 uri = refer_to->hvalue.ptr;
617 uri[refer_to->hvalue.slen] = '\0';
618
619 /* Now make the outgoing call. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000620 status = pjsua_make_call(existing_call->acc_index, uri, &new_call);
Benny Prijono26ff9062006-02-21 23:47:00 +0000621 if (status != PJ_SUCCESS) {
622
623 /* Notify xferer about the error */
624 status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
625 500, NULL, &tdata);
626 if (status != PJ_SUCCESS) {
627 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",
628 status);
629 return;
630 }
631 status = pjsip_xfer_send_request(sub, tdata);
632 if (status != PJ_SUCCESS) {
633 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",
634 status);
635 return;
636 }
637 return;
638 }
639
640 /* Put the server subscription in inv_data.
641 * Subsequent state changed in pjsua_inv_on_state_changed() will be
642 * reported back to the server subscription.
643 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000644 pjsua.calls[new_call].xfer_sub = sub;
Benny Prijono26ff9062006-02-21 23:47:00 +0000645
646 /* Put the invite_data in the subscription. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000647 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, &pjsua.calls[new_call]);
Benny Prijono26ff9062006-02-21 23:47:00 +0000648}
649
650
651/*
652 * This callback is called when transaction state has changed in INVITE
Benny Prijonob0808372006-03-02 21:18:58 +0000653 * session. We use this to trap:
654 * - incoming REFER request.
655 * - incoming MESSAGE request.
Benny Prijono26ff9062006-02-21 23:47:00 +0000656 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000657static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
658 pjsip_transaction *tsx,
659 pjsip_event *e)
Benny Prijono26ff9062006-02-21 23:47:00 +0000660{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000661 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
662
Benny Prijono26ff9062006-02-21 23:47:00 +0000663 if (tsx->role==PJSIP_ROLE_UAS &&
664 tsx->state==PJSIP_TSX_STATE_TRYING &&
665 pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0)
666 {
667 /*
668 * Incoming REFER request.
669 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000670 on_call_transfered(call->inv, e->body.tsx_state.src.rdata);
Benny Prijonob0808372006-03-02 21:18:58 +0000671
Benny Prijono26ff9062006-02-21 23:47:00 +0000672 }
Benny Prijonob0808372006-03-02 21:18:58 +0000673 else if (tsx->role==PJSIP_ROLE_UAS &&
674 tsx->state==PJSIP_TSX_STATE_TRYING &&
675 pjsip_method_cmp(&tsx->method, &pjsip_message_method)==0)
676 {
677 /*
678 * Incoming MESSAGE request!
679 */
680 pjsip_rx_data *rdata;
681 pjsip_msg *msg;
682 pjsip_accept_hdr *accept_hdr;
683 pj_status_t status;
684
685 rdata = e->body.tsx_state.src.rdata;
686 msg = rdata->msg_info.msg;
687
688 /* Request MUST have message body, with Content-Type equal to
689 * "text/plain".
690 */
691 if (pjsua_im_accept_pager(rdata, &accept_hdr) == PJ_FALSE) {
692
693 pjsip_hdr hdr_list;
694
695 pj_list_init(&hdr_list);
696 pj_list_push_back(&hdr_list, accept_hdr);
697
698 pjsip_dlg_respond( inv->dlg, rdata, PJSIP_SC_NOT_ACCEPTABLE_HERE,
699 NULL, &hdr_list, NULL );
700 return;
701 }
702
703 /* Respond with 200 first, so that remote doesn't retransmit in case
704 * the UI takes too long to process the message.
705 */
706 status = pjsip_dlg_respond( inv->dlg, rdata, 200, NULL, NULL, NULL);
707
708 /* Process MESSAGE request */
709 pjsua_im_process_pager(call->index, &inv->dlg->remote.info_str,
710 &inv->dlg->local.info_str, rdata);
711 }
712
Benny Prijono26ff9062006-02-21 23:47:00 +0000713}
714
715
716/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000717 * This callback is called by invite session framework when UAC session
718 * has forked.
719 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000720static void pjsua_call_on_forked( pjsip_inv_session *inv,
721 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000722{
723 PJ_UNUSED_ARG(inv);
724 PJ_UNUSED_ARG(e);
725
726 PJ_TODO(HANDLE_FORKED_DIALOG);
727}
728
729
730/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000731 * Create inactive SDP for call hold.
732 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000733static pj_status_t create_inactive_sdp(pjsua_call *call,
Benny Prijono26ff9062006-02-21 23:47:00 +0000734 pjmedia_sdp_session **p_answer)
735{
736 pj_status_t status;
737 pjmedia_sdp_conn *conn;
738 pjmedia_sdp_attr *attr;
739 pjmedia_sdp_session *sdp;
740
741 /* Create new offer */
742 status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000743 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +0000744 if (status != PJ_SUCCESS) {
745 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
746 return status;
747 }
748
749 /* Get SDP media connection line */
750 conn = sdp->media[0]->conn;
751 if (!conn)
752 conn = sdp->conn;
753
754 /* Modify address */
755 conn->addr = pj_str("0.0.0.0");
756
757 /* Remove existing directions attributes */
758 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
759 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
760 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
761 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
762
763 /* Add inactive attribute */
764 attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL);
765 pjmedia_sdp_media_add_attr(sdp->media[0], attr);
766
767 *p_answer = sdp;
768
769 return status;
770}
771
772/*
773 * Called when session received new offer.
774 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000775static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
776 const pjmedia_sdp_session *offer)
Benny Prijono26ff9062006-02-21 23:47:00 +0000777{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000778 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000779 pjmedia_sdp_conn *conn;
780 pjmedia_sdp_session *answer;
781 pj_bool_t is_remote_active;
782 pj_status_t status;
783
Benny Prijonoa91a0032006-02-26 21:23:45 +0000784 call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000785
786 /*
787 * See if remote is offering active media (i.e. not on-hold)
788 */
789 is_remote_active = PJ_TRUE;
790
791 conn = offer->media[0]->conn;
792 if (!conn)
793 conn = offer->conn;
794
795 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
796 pj_strcmp2(&conn->addr, "0")==0)
797 {
798 is_remote_active = PJ_FALSE;
799
800 }
801 else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))
802 {
803 is_remote_active = PJ_FALSE;
804 }
805
806 PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s",
807 (is_remote_active ? "active" : "inactive")));
808
809 /* Supply candidate answer */
810 if (is_remote_active) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000811 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
812 &call->skinfo, &answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000813 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000814 status = create_inactive_sdp( call, &answer );
Benny Prijono26ff9062006-02-21 23:47:00 +0000815 }
816
817 if (status != PJ_SUCCESS) {
818 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
819 return;
820 }
821
Benny Prijonoa91a0032006-02-26 21:23:45 +0000822 status = pjsip_inv_set_sdp_answer(call->inv, answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000823 if (status != PJ_SUCCESS) {
824 pjsua_perror(THIS_FILE, "Unable to set answer", status);
825 return;
826 }
827
828}
829
Benny Prijono1c2bf462006-03-05 11:54:02 +0000830/* Disconnect call */
831static void call_disconnect(pjsip_inv_session *inv,
832 int st_code)
833{
834 pjsip_tx_data *tdata;
835 pj_status_t status;
836
837 status = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
838 if (status == PJ_SUCCESS)
839 status = pjsip_inv_send_msg(inv, tdata, NULL);
840
841 if (status != PJ_SUCCESS) {
842 pjsua_perror(THIS_FILE, "Unable to disconnect call", status);
843 }
844}
Benny Prijono26ff9062006-02-21 23:47:00 +0000845
846/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000847 * Callback to be called when SDP offer/answer negotiation has just completed
848 * in the session. This function will start/update media if negotiation
849 * has succeeded.
850 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000851static void pjsua_call_on_media_update(pjsip_inv_session *inv,
852 pj_status_t status)
Benny Prijono84126ab2006-02-09 09:30:09 +0000853{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000854 pjsua_call *call;
Benny Prijono84126ab2006-02-09 09:30:09 +0000855 const pjmedia_sdp_session *local_sdp;
856 const pjmedia_sdp_session *remote_sdp;
Benny Prijono26ff9062006-02-21 23:47:00 +0000857 pjmedia_port *media_port;
858 pj_str_t port_name;
859 char tmp[PJSIP_MAX_URL_SIZE];
Benny Prijono84126ab2006-02-09 09:30:09 +0000860
Benny Prijonoa91a0032006-02-26 21:23:45 +0000861 call = inv->dlg->mod_data[pjsua.mod.id];
862
Benny Prijono84126ab2006-02-09 09:30:09 +0000863 if (status != PJ_SUCCESS) {
864
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000865 pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000866
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000867 /* Disconnect call if we're not in the middle of initializing an
868 * UAS dialog and if this is not a re-INVITE
869 */
870 if (inv->state != PJSIP_INV_STATE_NULL &&
871 inv->state != PJSIP_INV_STATE_CONFIRMED)
872 {
Benny Prijono1c2bf462006-03-05 11:54:02 +0000873 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
874 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000875 return;
876
877 }
878
879 /* Destroy existing media session, if any. */
880
Benny Prijonoa91a0032006-02-26 21:23:45 +0000881 if (call && call->session) {
882 pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
883 pjmedia_session_destroy(call->session);
884 call->session = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +0000885 }
886
887 /* Get local and remote SDP */
888
Benny Prijonoa91a0032006-02-26 21:23:45 +0000889 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000890 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000891 pjsua_perror(THIS_FILE,
892 "Unable to retrieve currently active local SDP",
893 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000894 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000895 return;
896 }
897
898
Benny Prijonoa91a0032006-02-26 21:23:45 +0000899 status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000900 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000901 pjsua_perror(THIS_FILE,
902 "Unable to retrieve currently active remote SDP",
903 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000904 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000905 return;
906 }
907
Benny Prijono84126ab2006-02-09 09:30:09 +0000908 /* Create new media session.
909 * The media session is active immediately.
910 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000911 if (pjsua.null_audio)
912 return;
913
914 status = pjmedia_session_create( pjsua.med_endpt, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000915 &call->skinfo,
Benny Prijono26ff9062006-02-21 23:47:00 +0000916 local_sdp, remote_sdp,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000917 call,
918 &call->session );
Benny Prijono26ff9062006-02-21 23:47:00 +0000919 if (status != PJ_SUCCESS) {
920 pjsua_perror(THIS_FILE, "Unable to create media session",
921 status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000922 call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono26ff9062006-02-21 23:47:00 +0000923 return;
Benny Prijono84126ab2006-02-09 09:30:09 +0000924 }
Benny Prijono26ff9062006-02-21 23:47:00 +0000925
926
927 /* Get the port interface of the first stream in the session.
928 * We need the port interface to add to the conference bridge.
929 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000930 pjmedia_session_get_port(call->session, 0, &media_port);
Benny Prijono26ff9062006-02-21 23:47:00 +0000931
932
933 /*
934 * Add the call to conference bridge.
935 */
936 port_name.ptr = tmp;
937 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000938 call->inv->dlg->remote.info->uri,
Benny Prijono26ff9062006-02-21 23:47:00 +0000939 tmp, sizeof(tmp));
940 if (port_name.slen < 1) {
941 port_name = pj_str("call");
942 }
Benny Prijonoa91a0032006-02-26 21:23:45 +0000943 status = pjmedia_conf_add_port( pjsua.mconf, call->inv->pool,
Benny Prijono26ff9062006-02-21 23:47:00 +0000944 media_port,
945 &port_name,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000946 &call->conf_slot);
Benny Prijono26ff9062006-02-21 23:47:00 +0000947 if (status != PJ_SUCCESS) {
948 pjsua_perror(THIS_FILE, "Unable to create conference slot",
949 status);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000950 pjmedia_session_destroy(call->session);
951 call->session = NULL;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000952 call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR);
Benny Prijono26ff9062006-02-21 23:47:00 +0000953 return;
954 }
955
Benny Prijono64f851e2006-02-23 13:49:28 +0000956 /* If auto-play is configured, connect the call to the file player
957 * port
Benny Prijono26ff9062006-02-21 23:47:00 +0000958 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000959 if (pjsua.auto_play && pjsua.wav_file &&
960 call->inv->role == PJSIP_ROLE_UAS)
961 {
Benny Prijono64f851e2006-02-23 13:49:28 +0000962
963 pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000964 call->conf_slot);
965
966 } else if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) {
967
968 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
969 call->conf_slot);
970
971 } else if (pjsua.auto_conf) {
972
973 int i;
974
975 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot);
976 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0);
977
978 for (i=0; i < pjsua.max_calls; ++i) {
979
980 if (!pjsua.calls[i].session)
981 continue;
982
983 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
984 pjsua.calls[i].conf_slot);
985 pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot,
986 call->conf_slot);
987 }
Benny Prijono64f851e2006-02-23 13:49:28 +0000988
989 } else {
990
991 /* Connect new call to the sound device port (port zero) in the
992 * main conference bridge.
993 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000994 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot);
995 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0);
Benny Prijono64f851e2006-02-23 13:49:28 +0000996 }
997
Benny Prijono26ff9062006-02-21 23:47:00 +0000998
999 /* Done. */
1000 {
1001 struct pjmedia_session_info sess_info;
1002 char info[80];
1003 int info_len = 0;
1004 unsigned i;
1005
Benny Prijonoa91a0032006-02-26 21:23:45 +00001006 pjmedia_session_get_info(call->session, &sess_info);
Benny Prijono26ff9062006-02-21 23:47:00 +00001007 for (i=0; i<sess_info.stream_cnt; ++i) {
1008 int len;
1009 const char *dir;
1010 pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
1011
1012 switch (strm_info->dir) {
1013 case PJMEDIA_DIR_NONE:
1014 dir = "inactive";
1015 break;
1016 case PJMEDIA_DIR_ENCODING:
1017 dir = "sendonly";
1018 break;
1019 case PJMEDIA_DIR_DECODING:
1020 dir = "recvonly";
1021 break;
1022 case PJMEDIA_DIR_ENCODING_DECODING:
1023 dir = "sendrecv";
1024 break;
1025 default:
1026 dir = "unknown";
1027 break;
1028 }
1029 len = pj_ansi_sprintf( info+info_len,
1030 ", stream #%d: %.*s (%s)", i,
1031 (int)strm_info->fmt.encoding_name.slen,
Benny Prijonoab7399b2006-02-27 00:40:31 +00001032 strm_info->fmt.encoding_name.ptr,
Benny Prijono26ff9062006-02-21 23:47:00 +00001033 dir);
1034 if (len > 0)
1035 info_len += len;
1036 }
1037 PJ_LOG(3,(THIS_FILE,"Media started%s", info));
1038 }
1039}
1040
1041
1042/*
1043 * Hangup call.
1044 */
Benny Prijono1c2bf462006-03-05 11:54:02 +00001045void pjsua_call_hangup(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001046{
Benny Prijonoa91a0032006-02-26 21:23:45 +00001047 pjsua_call *call;
Benny Prijono1c2bf462006-03-05 11:54:02 +00001048 int code;
Benny Prijono26ff9062006-02-21 23:47:00 +00001049 pj_status_t status;
1050 pjsip_tx_data *tdata;
1051
Benny Prijonoa91a0032006-02-26 21:23:45 +00001052
1053 call = &pjsua.calls[call_index];
1054
1055 if (!call->inv) {
1056 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1057 return;
1058 }
1059
Benny Prijono1c2bf462006-03-05 11:54:02 +00001060 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
1061 code = PJSIP_SC_OK;
1062 else if (call->inv->role == PJSIP_ROLE_UAS)
1063 code = PJSIP_SC_DECLINE;
1064 else
1065 code = PJSIP_SC_REQUEST_TERMINATED;
1066
Benny Prijonoa91a0032006-02-26 21:23:45 +00001067 status = pjsip_inv_end_session(call->inv, code, NULL, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001068 if (status != PJ_SUCCESS) {
1069 pjsua_perror(THIS_FILE,
1070 "Failed to create end session message",
1071 status);
1072 return;
1073 }
1074
Benny Prijonofccab712006-02-22 22:23:22 +00001075 /* pjsip_inv_end_session may return PJ_SUCCESS with NULL
1076 * as p_tdata when INVITE transaction has not been answered
1077 * with any provisional responses.
1078 */
1079 if (tdata == NULL)
1080 return;
1081
Benny Prijonoa91a0032006-02-26 21:23:45 +00001082 status = pjsip_inv_send_msg(call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +00001083 if (status != PJ_SUCCESS) {
1084 pjsua_perror(THIS_FILE,
1085 "Failed to send end session message",
1086 status);
1087 return;
1088 }
1089}
1090
1091
1092/*
1093 * Put call on-Hold.
1094 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001095void pjsua_call_set_hold(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001096{
1097 pjmedia_sdp_session *sdp;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001098 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001099 pjsip_tx_data *tdata;
1100 pj_status_t status;
1101
Benny Prijonoa91a0032006-02-26 21:23:45 +00001102 call = &pjsua.calls[call_index];
1103
1104 if (!call->inv) {
1105 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1106 return;
1107 }
1108
1109 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001110 PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
1111 return;
1112 }
1113
Benny Prijonoa91a0032006-02-26 21:23:45 +00001114 status = create_inactive_sdp(call, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001115 if (status != PJ_SUCCESS)
1116 return;
1117
1118 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001119 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001120 if (status != PJ_SUCCESS) {
1121 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1122 return;
1123 }
1124
Benny Prijonoa91a0032006-02-26 21:23:45 +00001125 status = pjsip_inv_send_msg( call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +00001126 if (status != PJ_SUCCESS) {
1127 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1128 return;
1129 }
1130}
1131
1132
1133/*
1134 * re-INVITE.
1135 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001136void pjsua_call_reinvite(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001137{
1138 pjmedia_sdp_session *sdp;
1139 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001140 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001141 pj_status_t status;
1142
Benny Prijonoa91a0032006-02-26 21:23:45 +00001143 call = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +00001144
Benny Prijonoa91a0032006-02-26 21:23:45 +00001145 if (!call->inv) {
1146 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1147 return;
1148 }
1149
1150
1151 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001152 PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
1153 return;
1154 }
1155
1156 /* Create SDP */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001157 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
1158 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001159 if (status != PJ_SUCCESS) {
Benny Prijonoa91a0032006-02-26 21:23:45 +00001160 pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",
1161 status);
Benny Prijono26ff9062006-02-21 23:47:00 +00001162 return;
1163 }
1164
1165 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001166 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001167 if (status != PJ_SUCCESS) {
1168 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1169 return;
1170 }
1171
Benny Prijonoa91a0032006-02-26 21:23:45 +00001172 status = pjsip_inv_send_msg( call->inv, tdata, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +00001173 if (status != PJ_SUCCESS) {
1174 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1175 return;
1176 }
1177}
1178
1179
1180/*
1181 * Transfer call.
1182 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001183void pjsua_call_xfer(int call_index, const char *dest)
Benny Prijono26ff9062006-02-21 23:47:00 +00001184{
1185 pjsip_evsub *sub;
1186 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001187 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001188 pj_str_t tmp;
1189 pj_status_t status;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001190
Benny Prijono26ff9062006-02-21 23:47:00 +00001191
Benny Prijonoa91a0032006-02-26 21:23:45 +00001192 call = &pjsua.calls[call_index];
1193
1194 if (!call->inv) {
1195 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1196 return;
1197 }
1198
Benny Prijono26ff9062006-02-21 23:47:00 +00001199 /* Create xfer client subscription.
1200 * We're not interested in knowing the transfer result, so we
1201 * put NULL as the callback.
1202 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001203 status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub);
Benny Prijono26ff9062006-02-21 23:47:00 +00001204 if (status != PJ_SUCCESS) {
1205 pjsua_perror(THIS_FILE, "Unable to create xfer", status);
1206 return;
1207 }
1208
1209 /*
1210 * Create REFER request.
1211 */
1212 status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
1213 if (status != PJ_SUCCESS) {
1214 pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
1215 return;
1216 }
1217
1218 /* Send. */
1219 status = pjsip_xfer_send_request(sub, tdata);
1220 if (status != PJ_SUCCESS) {
1221 pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
1222 return;
1223 }
1224
1225 /* For simplicity (that's what this program is intended to be!),
1226 * leave the original invite session as it is. More advanced application
1227 * may want to hold the INVITE, or terminate the invite, or whatever.
1228 */
Benny Prijono84126ab2006-02-09 09:30:09 +00001229}
Benny Prijono834aee32006-02-19 01:38:06 +00001230
1231
Benny Prijonob0808372006-03-02 21:18:58 +00001232/**
1233 * Send instant messaging inside INVITE session.
1234 */
1235void pjsua_call_send_im(int call_index, const char *str)
1236{
1237 pjsua_call *call;
1238 const pj_str_t mime_text = pj_str("text");
1239 const pj_str_t mime_plain = pj_str("plain");
1240 pj_str_t text;
1241 pjsip_tx_data *tdata;
1242 pj_status_t status;
1243
1244 call = &pjsua.calls[call_index];
1245
1246 if (!call->inv) {
1247 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1248 return;
1249 }
1250
1251 /* Lock dialog. */
1252 pjsip_dlg_inc_lock(call->inv->dlg);
1253
1254 /* Create request message. */
1255 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1256 -1, &tdata);
1257 if (status != PJ_SUCCESS) {
1258 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1259 goto on_return;
1260 }
1261
1262 /* Add accept header. */
1263 pjsip_msg_add_hdr( tdata->msg,
1264 (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
1265
1266 /* Create "text/plain" message body. */
1267 tdata->msg->body = pjsip_msg_body_create( tdata->pool, &mime_text,
1268 &mime_plain,
1269 pj_cstr(&text, str));
1270 if (tdata->msg->body == NULL) {
1271 pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM);
1272 pjsip_tx_data_dec_ref(tdata);
1273 goto on_return;
1274 }
1275
1276 /* Send the request. */
1277 status = pjsip_dlg_send_request( call->inv->dlg, tdata, NULL);
1278 if (status != PJ_SUCCESS) {
1279 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1280 goto on_return;
1281 }
1282
1283on_return:
1284 pjsip_dlg_dec_lock(call->inv->dlg);
1285}
1286
1287
1288/**
1289 * Send IM typing indication inside INVITE session.
1290 */
1291void pjsua_call_typing(int call_index, pj_bool_t is_typing)
1292{
1293 pjsua_call *call;
1294 pjsip_tx_data *tdata;
1295 pj_status_t status;
1296
1297 call = &pjsua.calls[call_index];
1298
1299 if (!call->inv) {
1300 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1301 return;
1302 }
1303
1304 /* Lock dialog. */
1305 pjsip_dlg_inc_lock(call->inv->dlg);
1306
1307 /* Create request message. */
1308 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1309 -1, &tdata);
1310 if (status != PJ_SUCCESS) {
1311 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1312 goto on_return;
1313 }
1314
1315 /* Create "application/im-iscomposing+xml" msg body. */
1316 tdata->msg->body = pjsip_iscomposing_create_body(tdata->pool, is_typing,
1317 NULL, NULL, -1);
1318
1319 /* Send the request. */
1320 status = pjsip_dlg_send_request( call->inv->dlg, tdata, NULL);
1321 if (status != PJ_SUCCESS) {
1322 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1323 goto on_return;
1324 }
1325
1326on_return:
1327 pjsip_dlg_dec_lock(call->inv->dlg);}
1328
1329
Benny Prijono834aee32006-02-19 01:38:06 +00001330/*
1331 * Terminate all calls.
1332 */
Benny Prijono1c2bf462006-03-05 11:54:02 +00001333void pjsua_call_hangup_all(void)
Benny Prijono834aee32006-02-19 01:38:06 +00001334{
Benny Prijonoa91a0032006-02-26 21:23:45 +00001335 int i;
Benny Prijono834aee32006-02-19 01:38:06 +00001336
Benny Prijonoa91a0032006-02-26 21:23:45 +00001337 for (i=0; i<pjsua.max_calls; ++i) {
Benny Prijono834aee32006-02-19 01:38:06 +00001338 pjsip_tx_data *tdata;
Benny Prijono1c2bf462006-03-05 11:54:02 +00001339 int st_code;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001340 pjsua_call *call;
Benny Prijono834aee32006-02-19 01:38:06 +00001341
Benny Prijonoa91a0032006-02-26 21:23:45 +00001342 if (pjsua.calls[i].inv == NULL)
1343 continue;
Benny Prijono834aee32006-02-19 01:38:06 +00001344
Benny Prijonoa91a0032006-02-26 21:23:45 +00001345 call = &pjsua.calls[i];
1346
Benny Prijono1c2bf462006-03-05 11:54:02 +00001347 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
1348 st_code = 200;
1349 } else {
1350 st_code = PJSIP_SC_GONE;
1351 }
1352
1353 if (pjsip_inv_end_session(call->inv, st_code, NULL, &tdata)==0) {
Benny Prijonofccab712006-02-22 22:23:22 +00001354 if (tdata)
Benny Prijonoa91a0032006-02-26 21:23:45 +00001355 pjsip_inv_send_msg(call->inv, tdata, NULL);
Benny Prijonofccab712006-02-22 22:23:22 +00001356 }
Benny Prijono834aee32006-02-19 01:38:06 +00001357 }
1358}
1359
Benny Prijono26ff9062006-02-21 23:47:00 +00001360
Benny Prijonoa91a0032006-02-26 21:23:45 +00001361pj_status_t pjsua_call_init(void)
1362{
1363 /* Initialize invite session callback. */
1364 pjsip_inv_callback inv_cb;
1365 pj_status_t status;
1366
1367 pj_memset(&inv_cb, 0, sizeof(inv_cb));
1368 inv_cb.on_state_changed = &pjsua_call_on_state_changed;
1369 inv_cb.on_new_session = &pjsua_call_on_forked;
1370 inv_cb.on_media_update = &pjsua_call_on_media_update;
1371 inv_cb.on_rx_offer = &pjsua_call_on_rx_offer;
1372 inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed;
1373
1374
1375 /* Initialize invite session module: */
1376 status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb);
1377
1378 return status;
1379}