blob: 73f5aac14c4a9d1d3eb367d1b5b4e312a96cb433 [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
Benny Prijono8befd9f2006-05-13 22:46:23 +000029#define THIS_FILE "pjsua_call.c"
Benny Prijono84126ab2006-02-09 09:30:09 +000030
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 Prijono275fd682006-03-22 11:59:11 +0000100/* Close and reopen socket. */
Benny Prijono46ecff82006-03-30 16:46:36 +0000101static pj_status_t reopen_sock( pj_sock_t *sock, pj_sockaddr_in *addr)
Benny Prijono275fd682006-03-22 11:59:11 +0000102{
Benny Prijono275fd682006-03-22 11:59:11 +0000103 pj_status_t status;
104
Benny Prijono275fd682006-03-22 11:59:11 +0000105 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, sock);
106 if (status != PJ_SUCCESS) {
107 pjsua_perror(THIS_FILE, "Unable to create socket", status);
108 return status;
109 }
110
Benny Prijono46ecff82006-03-30 16:46:36 +0000111 status = pj_sock_bind(*sock, addr, sizeof(pj_sockaddr_in));
Benny Prijono275fd682006-03-22 11:59:11 +0000112 if (status != PJ_SUCCESS) {
113 pjsua_perror(THIS_FILE, "Unable to re-bind RTP/RTCP socket", status);
114 return status;
115 }
116
117 return PJ_SUCCESS;
118}
119
120/*
121 * Destroy the call's media
122 */
123static pj_status_t call_destroy_media(int call_index)
124{
125 pjsua_call *call = &pjsua.calls[call_index];
126
127 if (call->conf_slot > 0) {
128 pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot);
129 call->conf_slot = 0;
130 }
131
132 if (call->session) {
Benny Prijono46ecff82006-03-30 16:46:36 +0000133 pj_sockaddr_in rtp_addr, rtcp_addr;
134 int addrlen;
135
136 addrlen = sizeof(rtp_addr);
137 pj_sock_getsockname(call->skinfo.rtp_sock, &rtp_addr, &addrlen);
138
139 addrlen = sizeof(rtcp_addr);
140 pj_sock_getsockname(call->skinfo.rtcp_sock, &rtcp_addr, &addrlen);
141
142 /* Destroy session (this will also close RTP/RTCP sockets). */
143 pjmedia_session_destroy(call->session);
Benny Prijono275fd682006-03-22 11:59:11 +0000144
145 /* Close and reopen RTP socket.
146 * This is necessary to get the socket unregistered from ioqueue,
147 * when IOCompletionPort is used.
148 */
Benny Prijono46ecff82006-03-30 16:46:36 +0000149 reopen_sock(&call->skinfo.rtp_sock, &rtp_addr);
Benny Prijono275fd682006-03-22 11:59:11 +0000150
151 /* Close and reopen RTCP socket too. */
Benny Prijono46ecff82006-03-30 16:46:36 +0000152 reopen_sock(&call->skinfo.rtcp_sock, &rtcp_addr);
Benny Prijono275fd682006-03-22 11:59:11 +0000153
Benny Prijono275fd682006-03-22 11:59:11 +0000154 call->session = NULL;
155
Benny Prijono8befd9f2006-05-13 22:46:23 +0000156 PJ_LOG(3,(THIS_FILE, "Media session for call %d is destroyed",
157 call_index));
Benny Prijono275fd682006-03-22 11:59:11 +0000158
Benny Prijono8befd9f2006-05-13 22:46:23 +0000159 }
Benny Prijono275fd682006-03-22 11:59:11 +0000160
161 return PJ_SUCCESS;
162}
163
164
Benny Prijono84126ab2006-02-09 09:30:09 +0000165/**
166 * Make outgoing call.
167 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000168pj_status_t pjsua_make_call(int acc_index,
169 const char *cstr_dest_uri,
170 int *p_call_index)
Benny Prijono84126ab2006-02-09 09:30:09 +0000171{
172 pj_str_t dest_uri;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000173 pjsip_dialog *dlg = NULL;
Benny Prijono84126ab2006-02-09 09:30:09 +0000174 pjmedia_sdp_session *offer;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000175 pjsip_inv_session *inv = NULL;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000176 int call_index = -1;
Benny Prijono84126ab2006-02-09 09:30:09 +0000177 pjsip_tx_data *tdata;
178 pj_status_t status;
179
180 /* Convert cstr_dest_uri to dest_uri */
181
182 dest_uri = pj_str((char*)cstr_dest_uri);
183
Benny Prijonoa91a0032006-02-26 21:23:45 +0000184 /* Find free call slot. */
185 for (call_index=0; call_index<pjsua.max_calls; ++call_index) {
186 if (pjsua.calls[call_index].inv == NULL)
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000187 break;
188 }
189
Benny Prijonoa91a0032006-02-26 21:23:45 +0000190 if (call_index == pjsua.max_calls) {
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000191 PJ_LOG(3,(THIS_FILE, "Error: too many calls!"));
192 return PJ_ETOOMANY;
193 }
194
Benny Prijonoe21e7842006-04-09 16:46:05 +0000195 /* Mark call start time. */
196 pj_gettimeofday(&pjsua.calls[call_index].start_time);
Benny Prijono84126ab2006-02-09 09:30:09 +0000197
Benny Prijonoe21e7842006-04-09 16:46:05 +0000198 /* Reset first response time */
199 pjsua.calls[call_index].res_time.sec = 0;
200
201 /* Create outgoing dialog: */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000202 status = pjsip_dlg_create_uac( pjsip_ua_instance(),
203 &pjsua.acc[acc_index].local_uri,
204 &pjsua.acc[acc_index].contact_uri,
205 &dest_uri, &dest_uri,
Benny Prijono84126ab2006-02-09 09:30:09 +0000206 &dlg);
207 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000208 pjsua_perror(THIS_FILE, "Dialog creation failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000209 return status;
210 }
211
212 /* Get media capability from media endpoint: */
213
Benny Prijonoa91a0032006-02-26 21:23:45 +0000214 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 1,
215 &pjsua.calls[call_index].skinfo,
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000216 &offer);
Benny Prijono84126ab2006-02-09 09:30:09 +0000217 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000218 pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000219 goto on_error;
220 }
221
222 /* Create the INVITE session: */
223
224 status = pjsip_inv_create_uac( dlg, offer, 0, &inv);
225 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000226 pjsua_perror(THIS_FILE, "Invite session creation failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000227 goto on_error;
228 }
229
230
231 /* Create and associate our data in the session. */
232
Benny Prijonoa91a0032006-02-26 21:23:45 +0000233 pjsua.calls[call_index].inv = inv;
234
235 dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
236 inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
Benny Prijono84126ab2006-02-09 09:30:09 +0000237
238
239 /* Set dialog Route-Set: */
240
Benny Prijonoa91a0032006-02-26 21:23:45 +0000241 if (!pj_list_empty(&pjsua.acc[acc_index].route_set))
242 pjsip_dlg_set_route_set(dlg, &pjsua.acc[acc_index].route_set);
Benny Prijono84126ab2006-02-09 09:30:09 +0000243
244
245 /* Set credentials: */
246
247 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,
248 pjsua.cred_info);
249
250
251 /* Create initial INVITE: */
252
253 status = pjsip_inv_invite(inv, &tdata);
254 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000255 pjsua_perror(THIS_FILE, "Unable to create initial INVITE request",
256 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000257 goto on_error;
258 }
259
260
261 /* Send initial INVITE: */
262
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000263 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono84126ab2006-02-09 09:30:09 +0000264 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000265 pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",
266 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000267 goto on_error;
268 }
269
270
271 /* Done. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000272
273 ++pjsua.call_cnt;
274
275 if (p_call_index)
276 *p_call_index = call_index;
Benny Prijono84126ab2006-02-09 09:30:09 +0000277
278 return PJ_SUCCESS;
279
280
281on_error:
Benny Prijono1c2bf462006-03-05 11:54:02 +0000282 if (inv != NULL) {
283 pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE);
284 } else {
285 pjsip_dlg_terminate(dlg);
286 }
287
Benny Prijonoa91a0032006-02-26 21:23:45 +0000288 if (call_index != -1) {
289 pjsua.calls[call_index].inv = NULL;
290 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000291 return status;
292}
293
294
295/**
296 * Handle incoming INVITE request.
297 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000298pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
Benny Prijono84126ab2006-02-09 09:30:09 +0000299{
300 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
301 pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
302 pjsip_msg *msg = rdata->msg_info.msg;
Benny Prijono26ff9062006-02-21 23:47:00 +0000303 pjsip_tx_data *response = NULL;
304 unsigned options = 0;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000305 pjsip_inv_session *inv = NULL;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000306 int acc_index;
307 int call_index = -1;
Benny Prijono26ff9062006-02-21 23:47:00 +0000308 pjmedia_sdp_session *answer;
Benny Prijono26ff9062006-02-21 23:47:00 +0000309 pj_status_t status;
Benny Prijono84126ab2006-02-09 09:30:09 +0000310
Benny Prijono26ff9062006-02-21 23:47:00 +0000311 /* Don't want to handle anything but INVITE */
312 if (msg->line.req.method.id != PJSIP_INVITE_METHOD)
313 return PJ_FALSE;
314
315 /* Don't want to handle anything that's already associated with
316 * existing dialog or transaction.
Benny Prijono84126ab2006-02-09 09:30:09 +0000317 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000318 if (dlg || tsx)
319 return PJ_FALSE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000320
Benny Prijono84126ab2006-02-09 09:30:09 +0000321
Benny Prijono26ff9062006-02-21 23:47:00 +0000322 /* Verify that we can handle the request. */
323 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
324 pjsua.endpt, &response);
325 if (status != PJ_SUCCESS) {
Benny Prijono84126ab2006-02-09 09:30:09 +0000326
Benny Prijono26ff9062006-02-21 23:47:00 +0000327 /*
328 * No we can't handle the incoming INVITE request.
329 */
Benny Prijono84126ab2006-02-09 09:30:09 +0000330
Benny Prijono26ff9062006-02-21 23:47:00 +0000331 if (response) {
332 pjsip_response_addr res_addr;
Benny Prijono84126ab2006-02-09 09:30:09 +0000333
Benny Prijono26ff9062006-02-21 23:47:00 +0000334 pjsip_get_response_addr(response->pool, rdata, &res_addr);
335 pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,
336 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000337
338 } else {
Benny Prijono84126ab2006-02-09 09:30:09 +0000339
Benny Prijono26ff9062006-02-21 23:47:00 +0000340 /* Respond with 500 (Internal Server Error) */
341 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
342 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000343 }
344
Benny Prijono26ff9062006-02-21 23:47:00 +0000345 return PJ_TRUE;
346 }
347
348
349 /*
350 * Yes we can handle the incoming INVITE request.
351 */
352
353 /* Find free call slot. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000354 for (call_index=0; call_index < pjsua.max_calls; ++call_index) {
355 if (pjsua.calls[call_index].inv == NULL)
Benny Prijono26ff9062006-02-21 23:47:00 +0000356 break;
357 }
358
Benny Prijonoa91a0032006-02-26 21:23:45 +0000359 if (call_index == PJSUA_MAX_CALLS) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000360 pjsip_endpt_respond_stateless(pjsua.endpt, rdata,
361 PJSIP_SC_BUSY_HERE, NULL,
362 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000363 return PJ_TRUE;
364 }
365
Benny Prijonoe21e7842006-04-09 16:46:05 +0000366 /* Mark call start time. */
367 pj_gettimeofday(&pjsua.calls[call_index].start_time);
368
369 /* Reset first response time */
370 pjsua.calls[call_index].res_time.sec = 0;
Benny Prijono26ff9062006-02-21 23:47:00 +0000371
Benny Prijono26ff9062006-02-21 23:47:00 +0000372 /* Get media capability from media endpoint: */
373
Benny Prijonoa91a0032006-02-26 21:23:45 +0000374 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 1,
375 &pjsua.calls[call_index].skinfo,
Benny Prijono26ff9062006-02-21 23:47:00 +0000376 &answer );
377 if (status != PJ_SUCCESS) {
378 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
379 NULL, NULL);
380
Benny Prijono26ff9062006-02-21 23:47:00 +0000381 return PJ_TRUE;
382 }
383
Benny Prijonoa91a0032006-02-26 21:23:45 +0000384 /* TODO:
385 *
386 * Get which account is most likely to be associated with this incoming
387 * call. We need the account to find which contact URI to put for
388 * the call.
389 */
390 acc_index = 0;
391
Benny Prijono26ff9062006-02-21 23:47:00 +0000392 /* Create dialog: */
393
394 status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000395 &pjsua.acc[acc_index].contact_uri,
396 &dlg);
Benny Prijono26ff9062006-02-21 23:47:00 +0000397 if (status != PJ_SUCCESS) {
398 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
399 NULL, NULL);
400
Benny Prijono26ff9062006-02-21 23:47:00 +0000401 return PJ_TRUE;
402 }
403
404
405 /* Create invite session: */
406
407 status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
408 if (status != PJ_SUCCESS) {
409
Benny Prijonob0808372006-03-02 21:18:58 +0000410 pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000411 pjsip_dlg_terminate(dlg);
Benny Prijono26ff9062006-02-21 23:47:00 +0000412 return PJ_TRUE;
413 }
414
415
416 /* Create and attach pjsua data to the dialog: */
417
Benny Prijonoa91a0032006-02-26 21:23:45 +0000418 pjsua.calls[call_index].inv = inv;
Benny Prijono26ff9062006-02-21 23:47:00 +0000419
Benny Prijonoa91a0032006-02-26 21:23:45 +0000420 dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
421 inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +0000422
423
Benny Prijono64f851e2006-02-23 13:49:28 +0000424 /* Must answer with some response to initial INVITE.
425 * If auto-answer flag is set, send 200 straight away, otherwise send 100.
426 */
427
428 status = pjsip_inv_initial_answer(inv, rdata,
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000429 (pjsua.auto_answer ? pjsua.auto_answer
430 : 100),
Benny Prijono64f851e2006-02-23 13:49:28 +0000431 NULL, NULL, &response);
Benny Prijono26ff9062006-02-21 23:47:00 +0000432 if (status != PJ_SUCCESS) {
433
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000434 int st_code;
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000435
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000436 pjsua_perror(THIS_FILE, "Unable to send answer to incoming INVITE",
437 status);
438
439 /* If failed to send 2xx response, there's a good chance that it is
440 * because SDP negotiation has failed.
441 */
442 if (pjsua.auto_answer/100 == 2)
443 st_code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
444 else
445 st_code = 500;
446
447 pjsip_dlg_respond(dlg, rdata, st_code, NULL, NULL, NULL);
448 pjsip_inv_terminate(inv, st_code, PJ_FALSE);
449 return PJ_TRUE;
Benny Prijono26ff9062006-02-21 23:47:00 +0000450
451 } else {
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000452 status = pjsip_inv_send_msg(inv, response);
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000453 if (status != PJ_SUCCESS)
454 pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
Benny Prijono26ff9062006-02-21 23:47:00 +0000455 }
456
Benny Prijono64f851e2006-02-23 13:49:28 +0000457 if (pjsua.auto_answer < 200) {
458 PJ_LOG(3,(THIS_FILE,
459 "\nIncoming call!!\n"
460 "From: %.*s\n"
461 "To: %.*s\n"
462 "(press 'a' to answer, 'h' to decline)",
463 (int)dlg->remote.info_str.slen,
464 dlg->remote.info_str.ptr,
465 (int)dlg->local.info_str.slen,
466 dlg->local.info_str.ptr));
467 } else {
468 PJ_LOG(3,(THIS_FILE,
469 "Call From:%.*s To:%.*s was answered with %d (%s)",
470 (int)dlg->remote.info_str.slen,
471 dlg->remote.info_str.ptr,
472 (int)dlg->local.info_str.slen,
473 dlg->local.info_str.ptr,
474 pjsua.auto_answer,
475 pjsip_get_status_text(pjsua.auto_answer)->ptr ));
476 }
477
Benny Prijonoa91a0032006-02-26 21:23:45 +0000478 ++pjsua.call_cnt;
479
Benny Prijono105217f2006-03-06 16:25:59 +0000480 /* Schedule timer to refresh. */
481 if (pjsua.uas_refresh > 0) {
482 schedule_call_timer( &pjsua.calls[call_index],
483 &pjsua.calls[call_index].refresh_tm,
484 REFRESH_CALL_TIMER,
485 pjsua.uas_refresh);
486 }
487
488 /* Schedule timer to hangup call. */
489 if (pjsua.uas_duration > 0) {
490 schedule_call_timer( &pjsua.calls[call_index],
491 &pjsua.calls[call_index].hangup_tm,
492 HANGUP_CALL_TIMER,
493 pjsua.uas_duration);
494 }
495
Benny Prijono26ff9062006-02-21 23:47:00 +0000496 /* This INVITE request has been handled. */
497 return PJ_TRUE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000498}
499
500
501/*
502 * This callback receives notification from invite session when the
503 * session state has changed.
504 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000505static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
506 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000507{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000508 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000509
Benny Prijonoe21e7842006-04-09 16:46:05 +0000510 if (!call)
511 return;
512
513 /* Get call times */
514 switch (inv->state) {
515 case PJSIP_INV_STATE_EARLY:
516 case PJSIP_INV_STATE_CONNECTING:
517 if (call->res_time.sec == 0)
518 pj_gettimeofday(&call->res_time);
519 break;
520 case PJSIP_INV_STATE_CONFIRMED:
521 pj_gettimeofday(&call->conn_time);
522 break;
523 case PJSIP_INV_STATE_DISCONNECTED:
524 pj_gettimeofday(&call->dis_time);
525 break;
Benny Prijono8befd9f2006-05-13 22:46:23 +0000526 default:
527 /* Nothing to do. Just to keep gcc from complaining about
528 * unused enums.
529 */
530 break;
Benny Prijonoe21e7842006-04-09 16:46:05 +0000531 }
532
Benny Prijono26ff9062006-02-21 23:47:00 +0000533 /* If this is an outgoing INVITE that was created because of
534 * REFER/transfer, send NOTIFY to transferer.
535 */
Benny Prijonoe21e7842006-04-09 16:46:05 +0000536 if (call->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000537 int st_code = -1;
538 pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
539
540
Benny Prijonoa91a0032006-02-26 21:23:45 +0000541 switch (call->inv->state) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000542 case PJSIP_INV_STATE_NULL:
543 case PJSIP_INV_STATE_CALLING:
544 /* Do nothing */
545 break;
546
547 case PJSIP_INV_STATE_EARLY:
548 case PJSIP_INV_STATE_CONNECTING:
549 st_code = e->body.tsx_state.tsx->status_code;
550 ev_state = PJSIP_EVSUB_STATE_ACTIVE;
551 break;
552
553 case PJSIP_INV_STATE_CONFIRMED:
554 /* When state is confirmed, send the final 200/OK and terminate
555 * subscription.
556 */
557 st_code = e->body.tsx_state.tsx->status_code;
558 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
559 break;
560
561 case PJSIP_INV_STATE_DISCONNECTED:
562 st_code = e->body.tsx_state.tsx->status_code;
563 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
564 break;
Benny Prijono8befd9f2006-05-13 22:46:23 +0000565
566 default:
567 /* Nothing to do. Just to keep gcc from complaining about
568 * unused enums.
569 */
570 break;
Benny Prijono26ff9062006-02-21 23:47:00 +0000571 }
572
573 if (st_code != -1) {
574 pjsip_tx_data *tdata;
575 pj_status_t status;
576
Benny Prijonoa91a0032006-02-26 21:23:45 +0000577 status = pjsip_xfer_notify( call->xfer_sub,
Benny Prijono26ff9062006-02-21 23:47:00 +0000578 ev_state, st_code,
579 NULL, &tdata);
580 if (status != PJ_SUCCESS) {
581 pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);
582 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000583 status = pjsip_xfer_send_request(call->xfer_sub, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +0000584 if (status != PJ_SUCCESS) {
585 pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);
586 }
587 }
588 }
589 }
590
Benny Prijono84126ab2006-02-09 09:30:09 +0000591
Benny Prijonob0808372006-03-02 21:18:58 +0000592 pjsua_ui_on_call_state(call->index, e);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000593
594 /* call->inv may be NULL now */
595
Benny Prijono84126ab2006-02-09 09:30:09 +0000596 /* Destroy media session when invite session is disconnected. */
597 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono632ce712006-02-09 14:01:40 +0000598
Benny Prijonoa91a0032006-02-26 21:23:45 +0000599 pj_assert(call != NULL);
Benny Prijono632ce712006-02-09 14:01:40 +0000600
Benny Prijono275fd682006-03-22 11:59:11 +0000601 if (call)
602 call_destroy_media(call->index);
Benny Prijono84126ab2006-02-09 09:30:09 +0000603
Benny Prijono105217f2006-03-06 16:25:59 +0000604 /* Remove timers. */
605 schedule_call_timer(call, &call->refresh_tm, REFRESH_CALL_TIMER, 0);
606 schedule_call_timer(call, &call->hangup_tm, HANGUP_CALL_TIMER, 0);
607
608 /* Free call */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000609 call->inv = NULL;
610 --pjsua.call_cnt;
Benny Prijono84126ab2006-02-09 09:30:09 +0000611 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000612}
613
614
615/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000616 * Callback called by event framework when the xfer subscription state
617 * has changed.
618 */
619static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
620{
621
622 PJ_UNUSED_ARG(event);
623
624 /*
625 * We're only interested when subscription is terminated, to
626 * clear the xfer_sub member of the inv_data.
627 */
628 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000629 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000630
Benny Prijonoa91a0032006-02-26 21:23:45 +0000631 call = pjsip_evsub_get_mod_data(sub, pjsua.mod.id);
632 if (!call)
Benny Prijono26ff9062006-02-21 23:47:00 +0000633 return;
634
635 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000636 call->xfer_sub = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +0000637
638 PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated"));
639 }
640}
641
642
643/*
644 * Follow transfer (REFER) request.
645 */
646static void on_call_transfered( pjsip_inv_session *inv,
647 pjsip_rx_data *rdata )
648{
649 pj_status_t status;
650 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000651 pjsua_call *existing_call;
652 int new_call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000653 const pj_str_t str_refer_to = { "Refer-To", 8};
654 pjsip_generic_string_hdr *refer_to;
655 char *uri;
656 struct pjsip_evsub_user xfer_cb;
657 pjsip_evsub *sub;
658
Benny Prijonoa91a0032006-02-26 21:23:45 +0000659 existing_call = inv->dlg->mod_data[pjsua.mod.id];
660
Benny Prijono26ff9062006-02-21 23:47:00 +0000661 /* Find the Refer-To header */
662 refer_to = (pjsip_generic_string_hdr*)
663 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
664
665 if (refer_to == NULL) {
666 /* Invalid Request.
667 * No Refer-To header!
668 */
669 PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!"));
Benny Prijonob0808372006-03-02 21:18:58 +0000670 pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000671 return;
672 }
673
674 PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s",
675 (int)inv->dlg->remote.info_str.slen,
676 inv->dlg->remote.info_str.ptr,
677 (int)refer_to->hvalue.slen,
678 refer_to->hvalue.ptr));
679
680 /* Init callback */
681 pj_memset(&xfer_cb, 0, sizeof(xfer_cb));
682 xfer_cb.on_evsub_state = &xfer_on_evsub_state;
683
684 /* Create transferee event subscription */
685 status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
686 if (status != PJ_SUCCESS) {
687 pjsua_perror(THIS_FILE, "Unable to create xfer uas", status);
Benny Prijonob0808372006-03-02 21:18:58 +0000688 pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000689 return;
690 }
691
692 /* Accept the REFER request, send 200 (OK). */
693 pjsip_xfer_accept(sub, rdata, 200, NULL);
694
695 /* Create initial NOTIFY request */
696 status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
697 100, NULL, &tdata);
698 if (status != PJ_SUCCESS) {
699 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status);
700 return;
701 }
702
703 /* Send initial NOTIFY request */
704 status = pjsip_xfer_send_request( sub, tdata);
705 if (status != PJ_SUCCESS) {
706 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status);
707 return;
708 }
709
710 /* We're cheating here.
711 * We need to get a null terminated string from a pj_str_t.
712 * So grab the pointer from the hvalue and NULL terminate it, knowing
713 * that the NULL position will be occupied by a newline.
714 */
715 uri = refer_to->hvalue.ptr;
716 uri[refer_to->hvalue.slen] = '\0';
717
718 /* Now make the outgoing call. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000719 status = pjsua_make_call(existing_call->acc_index, uri, &new_call);
Benny Prijono26ff9062006-02-21 23:47:00 +0000720 if (status != PJ_SUCCESS) {
721
722 /* Notify xferer about the error */
723 status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
724 500, NULL, &tdata);
725 if (status != PJ_SUCCESS) {
726 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",
727 status);
728 return;
729 }
730 status = pjsip_xfer_send_request(sub, tdata);
731 if (status != PJ_SUCCESS) {
732 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",
733 status);
734 return;
735 }
736 return;
737 }
738
739 /* Put the server subscription in inv_data.
740 * Subsequent state changed in pjsua_inv_on_state_changed() will be
741 * reported back to the server subscription.
742 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000743 pjsua.calls[new_call].xfer_sub = sub;
Benny Prijono26ff9062006-02-21 23:47:00 +0000744
745 /* Put the invite_data in the subscription. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000746 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, &pjsua.calls[new_call]);
Benny Prijono26ff9062006-02-21 23:47:00 +0000747}
748
749
750/*
751 * This callback is called when transaction state has changed in INVITE
Benny Prijonob0808372006-03-02 21:18:58 +0000752 * session. We use this to trap:
753 * - incoming REFER request.
754 * - incoming MESSAGE request.
Benny Prijono26ff9062006-02-21 23:47:00 +0000755 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000756static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
757 pjsip_transaction *tsx,
758 pjsip_event *e)
Benny Prijono26ff9062006-02-21 23:47:00 +0000759{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000760 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
761
Benny Prijono26ff9062006-02-21 23:47:00 +0000762 if (tsx->role==PJSIP_ROLE_UAS &&
763 tsx->state==PJSIP_TSX_STATE_TRYING &&
764 pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0)
765 {
766 /*
767 * Incoming REFER request.
768 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000769 on_call_transfered(call->inv, e->body.tsx_state.src.rdata);
Benny Prijonob0808372006-03-02 21:18:58 +0000770
Benny Prijono26ff9062006-02-21 23:47:00 +0000771 }
Benny Prijonob0808372006-03-02 21:18:58 +0000772 else if (tsx->role==PJSIP_ROLE_UAS &&
773 tsx->state==PJSIP_TSX_STATE_TRYING &&
774 pjsip_method_cmp(&tsx->method, &pjsip_message_method)==0)
775 {
776 /*
777 * Incoming MESSAGE request!
778 */
779 pjsip_rx_data *rdata;
780 pjsip_msg *msg;
781 pjsip_accept_hdr *accept_hdr;
782 pj_status_t status;
783
784 rdata = e->body.tsx_state.src.rdata;
785 msg = rdata->msg_info.msg;
786
787 /* Request MUST have message body, with Content-Type equal to
788 * "text/plain".
789 */
790 if (pjsua_im_accept_pager(rdata, &accept_hdr) == PJ_FALSE) {
791
792 pjsip_hdr hdr_list;
793
794 pj_list_init(&hdr_list);
795 pj_list_push_back(&hdr_list, accept_hdr);
796
797 pjsip_dlg_respond( inv->dlg, rdata, PJSIP_SC_NOT_ACCEPTABLE_HERE,
798 NULL, &hdr_list, NULL );
799 return;
800 }
801
802 /* Respond with 200 first, so that remote doesn't retransmit in case
803 * the UI takes too long to process the message.
804 */
805 status = pjsip_dlg_respond( inv->dlg, rdata, 200, NULL, NULL, NULL);
806
807 /* Process MESSAGE request */
808 pjsua_im_process_pager(call->index, &inv->dlg->remote.info_str,
809 &inv->dlg->local.info_str, rdata);
810 }
811
Benny Prijono26ff9062006-02-21 23:47:00 +0000812}
813
814
815/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000816 * This callback is called by invite session framework when UAC session
817 * has forked.
818 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000819static void pjsua_call_on_forked( pjsip_inv_session *inv,
820 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000821{
822 PJ_UNUSED_ARG(inv);
823 PJ_UNUSED_ARG(e);
824
825 PJ_TODO(HANDLE_FORKED_DIALOG);
826}
827
828
829/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000830 * Create inactive SDP for call hold.
831 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000832static pj_status_t create_inactive_sdp(pjsua_call *call,
Benny Prijono26ff9062006-02-21 23:47:00 +0000833 pjmedia_sdp_session **p_answer)
834{
835 pj_status_t status;
836 pjmedia_sdp_conn *conn;
837 pjmedia_sdp_attr *attr;
838 pjmedia_sdp_session *sdp;
839
840 /* Create new offer */
841 status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000842 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +0000843 if (status != PJ_SUCCESS) {
844 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
845 return status;
846 }
847
848 /* Get SDP media connection line */
849 conn = sdp->media[0]->conn;
850 if (!conn)
851 conn = sdp->conn;
852
853 /* Modify address */
854 conn->addr = pj_str("0.0.0.0");
855
856 /* Remove existing directions attributes */
857 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
858 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
859 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
860 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
861
862 /* Add inactive attribute */
863 attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL);
864 pjmedia_sdp_media_add_attr(sdp->media[0], attr);
865
866 *p_answer = sdp;
867
868 return status;
869}
870
871/*
872 * Called when session received new offer.
873 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000874static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
875 const pjmedia_sdp_session *offer)
Benny Prijono26ff9062006-02-21 23:47:00 +0000876{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000877 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000878 pjmedia_sdp_conn *conn;
879 pjmedia_sdp_session *answer;
880 pj_bool_t is_remote_active;
881 pj_status_t status;
882
Benny Prijonoa91a0032006-02-26 21:23:45 +0000883 call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000884
885 /*
886 * See if remote is offering active media (i.e. not on-hold)
887 */
888 is_remote_active = PJ_TRUE;
889
890 conn = offer->media[0]->conn;
891 if (!conn)
892 conn = offer->conn;
893
894 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
895 pj_strcmp2(&conn->addr, "0")==0)
896 {
897 is_remote_active = PJ_FALSE;
898
899 }
900 else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))
901 {
902 is_remote_active = PJ_FALSE;
903 }
904
905 PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s",
906 (is_remote_active ? "active" : "inactive")));
907
908 /* Supply candidate answer */
909 if (is_remote_active) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000910 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
911 &call->skinfo, &answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000912 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000913 status = create_inactive_sdp( call, &answer );
Benny Prijono26ff9062006-02-21 23:47:00 +0000914 }
915
916 if (status != PJ_SUCCESS) {
917 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
918 return;
919 }
920
Benny Prijonoa91a0032006-02-26 21:23:45 +0000921 status = pjsip_inv_set_sdp_answer(call->inv, answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000922 if (status != PJ_SUCCESS) {
923 pjsua_perror(THIS_FILE, "Unable to set answer", status);
924 return;
925 }
926
927}
928
Benny Prijono8befd9f2006-05-13 22:46:23 +0000929#if 0
Benny Prijono1c2bf462006-03-05 11:54:02 +0000930/* Disconnect call */
931static void call_disconnect(pjsip_inv_session *inv,
932 int st_code)
933{
934 pjsip_tx_data *tdata;
935 pj_status_t status;
936
937 status = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
938 if (status == PJ_SUCCESS)
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000939 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000940
941 if (status != PJ_SUCCESS) {
942 pjsua_perror(THIS_FILE, "Unable to disconnect call", status);
943 }
944}
Benny Prijono8befd9f2006-05-13 22:46:23 +0000945#endif
Benny Prijono26ff9062006-02-21 23:47:00 +0000946
947/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000948 * Callback to be called when SDP offer/answer negotiation has just completed
949 * in the session. This function will start/update media if negotiation
950 * has succeeded.
951 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000952static void pjsua_call_on_media_update(pjsip_inv_session *inv,
953 pj_status_t status)
Benny Prijono84126ab2006-02-09 09:30:09 +0000954{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000955 pjsua_call *call;
Benny Prijono8befd9f2006-05-13 22:46:23 +0000956 pjmedia_session_info sess_info;
Benny Prijono84126ab2006-02-09 09:30:09 +0000957 const pjmedia_sdp_session *local_sdp;
958 const pjmedia_sdp_session *remote_sdp;
Benny Prijono26ff9062006-02-21 23:47:00 +0000959 pjmedia_port *media_port;
960 pj_str_t port_name;
961 char tmp[PJSIP_MAX_URL_SIZE];
Benny Prijono84126ab2006-02-09 09:30:09 +0000962
Benny Prijonoa91a0032006-02-26 21:23:45 +0000963 call = inv->dlg->mod_data[pjsua.mod.id];
964
Benny Prijono84126ab2006-02-09 09:30:09 +0000965 if (status != PJ_SUCCESS) {
966
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000967 pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000968
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000969 /* Disconnect call if we're not in the middle of initializing an
970 * UAS dialog and if this is not a re-INVITE
971 */
972 if (inv->state != PJSIP_INV_STATE_NULL &&
973 inv->state != PJSIP_INV_STATE_CONFIRMED)
974 {
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000975 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000976 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000977 return;
978
979 }
980
981 /* Destroy existing media session, if any. */
982
Benny Prijono275fd682006-03-22 11:59:11 +0000983 if (call)
984 call_destroy_media(call->index);
Benny Prijono84126ab2006-02-09 09:30:09 +0000985
986 /* Get local and remote SDP */
987
Benny Prijonoa91a0032006-02-26 21:23:45 +0000988 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000989 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000990 pjsua_perror(THIS_FILE,
991 "Unable to retrieve currently active local SDP",
992 status);
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000993 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000994 return;
995 }
996
997
Benny Prijonoa91a0032006-02-26 21:23:45 +0000998 status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000999 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +00001000 pjsua_perror(THIS_FILE,
1001 "Unable to retrieve currently active remote SDP",
1002 status);
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001003 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +00001004 return;
1005 }
1006
Benny Prijono26ff9062006-02-21 23:47:00 +00001007 if (pjsua.null_audio)
1008 return;
Benny Prijono8befd9f2006-05-13 22:46:23 +00001009
1010 /* Create media session info based on SDP parameters.
1011 * We only support one stream per session at the moment
1012 */
1013 status = pjmedia_session_info_from_sdp( call->inv->dlg->pool,
1014 pjsua.med_endpt, 1,
1015 &sess_info, &call->skinfo,
1016 local_sdp, remote_sdp);
1017 if (status != PJ_SUCCESS) {
1018 pjsua_perror(THIS_FILE, "Unable to create media session",
1019 status);
1020 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
1021 return;
1022 }
1023
1024 /* Override ptime, if this option is specified. */
1025 if (pjsua.ptime) {
1026 sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t)
1027 (pjsua.ptime / sess_info.stream_info[0].param->info.frm_ptime);
1028 if (sess_info.stream_info[0].param->setting.frm_per_pkt==0)
1029 sess_info.stream_info[0].param->setting.frm_per_pkt = 1;
1030 }
1031
1032 /* Optionally, application may modify other stream settings here
1033 * (such as jitter buffer parameters, codec ptime, etc.)
1034 */
1035
1036 /* Create session based on session info. */
1037 status = pjmedia_session_create( pjsua.med_endpt, &sess_info,
1038 call, &call->session );
Benny Prijono26ff9062006-02-21 23:47:00 +00001039 if (status != PJ_SUCCESS) {
1040 pjsua_perror(THIS_FILE, "Unable to create media session",
1041 status);
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001042 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono26ff9062006-02-21 23:47:00 +00001043 return;
Benny Prijono84126ab2006-02-09 09:30:09 +00001044 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001045
1046
1047 /* Get the port interface of the first stream in the session.
1048 * We need the port interface to add to the conference bridge.
1049 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001050 pjmedia_session_get_port(call->session, 0, &media_port);
Benny Prijono26ff9062006-02-21 23:47:00 +00001051
1052
1053 /*
1054 * Add the call to conference bridge.
1055 */
1056 port_name.ptr = tmp;
1057 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
Benny Prijonoa91a0032006-02-26 21:23:45 +00001058 call->inv->dlg->remote.info->uri,
Benny Prijono26ff9062006-02-21 23:47:00 +00001059 tmp, sizeof(tmp));
1060 if (port_name.slen < 1) {
1061 port_name = pj_str("call");
1062 }
Benny Prijonoa91a0032006-02-26 21:23:45 +00001063 status = pjmedia_conf_add_port( pjsua.mconf, call->inv->pool,
Benny Prijono26ff9062006-02-21 23:47:00 +00001064 media_port,
1065 &port_name,
Benny Prijonoa91a0032006-02-26 21:23:45 +00001066 &call->conf_slot);
Benny Prijono26ff9062006-02-21 23:47:00 +00001067 if (status != PJ_SUCCESS) {
1068 pjsua_perror(THIS_FILE, "Unable to create conference slot",
1069 status);
Benny Prijono275fd682006-03-22 11:59:11 +00001070 call_destroy_media(call->index);
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001071 //call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR);
Benny Prijono26ff9062006-02-21 23:47:00 +00001072 return;
1073 }
1074
Benny Prijono64f851e2006-02-23 13:49:28 +00001075 /* If auto-play is configured, connect the call to the file player
1076 * port
Benny Prijono26ff9062006-02-21 23:47:00 +00001077 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001078 if (pjsua.auto_play && pjsua.wav_file &&
1079 call->inv->role == PJSIP_ROLE_UAS)
1080 {
Benny Prijono64f851e2006-02-23 13:49:28 +00001081
1082 pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,
Benny Prijonob100d692006-03-17 00:16:01 +00001083 call->conf_slot, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001084
Benny Prijonob8c25182006-04-29 08:31:09 +00001085 }
1086 if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) {
Benny Prijonoa91a0032006-02-26 21:23:45 +00001087
1088 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
Benny Prijonob100d692006-03-17 00:16:01 +00001089 call->conf_slot, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001090
Benny Prijonob8c25182006-04-29 08:31:09 +00001091 }
1092 if (pjsua.auto_conf) {
Benny Prijonoa91a0032006-02-26 21:23:45 +00001093 int i;
1094
Benny Prijonob100d692006-03-17 00:16:01 +00001095 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0);
1096 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001097
1098 for (i=0; i < pjsua.max_calls; ++i) {
1099
1100 if (!pjsua.calls[i].session)
1101 continue;
1102
1103 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
Benny Prijonob100d692006-03-17 00:16:01 +00001104 pjsua.calls[i].conf_slot, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001105 pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot,
Benny Prijonob100d692006-03-17 00:16:01 +00001106 call->conf_slot, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001107 }
Benny Prijono64f851e2006-02-23 13:49:28 +00001108
Benny Prijonob8c25182006-04-29 08:31:09 +00001109 }
1110
1111 /* Normal operation: if no auto_xx is given, connect new call to
1112 * the sound device port (port zero) in the main conference bridge.
1113 */
1114 if (pjsua.auto_play == 0 && pjsua.auto_loop == 0 &&
1115 pjsua.auto_conf == 0)
1116 {
Benny Prijonob100d692006-03-17 00:16:01 +00001117 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0);
1118 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0);
Benny Prijono64f851e2006-02-23 13:49:28 +00001119 }
1120
Benny Prijono26ff9062006-02-21 23:47:00 +00001121
1122 /* Done. */
1123 {
1124 struct pjmedia_session_info sess_info;
1125 char info[80];
1126 int info_len = 0;
1127 unsigned i;
1128
Benny Prijonoa91a0032006-02-26 21:23:45 +00001129 pjmedia_session_get_info(call->session, &sess_info);
Benny Prijono26ff9062006-02-21 23:47:00 +00001130 for (i=0; i<sess_info.stream_cnt; ++i) {
1131 int len;
1132 const char *dir;
1133 pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
1134
1135 switch (strm_info->dir) {
1136 case PJMEDIA_DIR_NONE:
1137 dir = "inactive";
1138 break;
1139 case PJMEDIA_DIR_ENCODING:
1140 dir = "sendonly";
1141 break;
1142 case PJMEDIA_DIR_DECODING:
1143 dir = "recvonly";
1144 break;
1145 case PJMEDIA_DIR_ENCODING_DECODING:
1146 dir = "sendrecv";
1147 break;
1148 default:
1149 dir = "unknown";
1150 break;
1151 }
1152 len = pj_ansi_sprintf( info+info_len,
1153 ", stream #%d: %.*s (%s)", i,
1154 (int)strm_info->fmt.encoding_name.slen,
Benny Prijonoab7399b2006-02-27 00:40:31 +00001155 strm_info->fmt.encoding_name.ptr,
Benny Prijono26ff9062006-02-21 23:47:00 +00001156 dir);
1157 if (len > 0)
1158 info_len += len;
1159 }
1160 PJ_LOG(3,(THIS_FILE,"Media started%s", info));
1161 }
1162}
1163
1164
1165/*
1166 * Hangup call.
1167 */
Benny Prijono1c2bf462006-03-05 11:54:02 +00001168void pjsua_call_hangup(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001169{
Benny Prijonoa91a0032006-02-26 21:23:45 +00001170 pjsua_call *call;
Benny Prijono1c2bf462006-03-05 11:54:02 +00001171 int code;
Benny Prijono26ff9062006-02-21 23:47:00 +00001172 pj_status_t status;
1173 pjsip_tx_data *tdata;
1174
Benny Prijonoa91a0032006-02-26 21:23:45 +00001175
1176 call = &pjsua.calls[call_index];
1177
1178 if (!call->inv) {
1179 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1180 return;
1181 }
1182
Benny Prijono1c2bf462006-03-05 11:54:02 +00001183 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
1184 code = PJSIP_SC_OK;
1185 else if (call->inv->role == PJSIP_ROLE_UAS)
1186 code = PJSIP_SC_DECLINE;
1187 else
1188 code = PJSIP_SC_REQUEST_TERMINATED;
1189
Benny Prijonoa91a0032006-02-26 21:23:45 +00001190 status = pjsip_inv_end_session(call->inv, code, NULL, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001191 if (status != PJ_SUCCESS) {
1192 pjsua_perror(THIS_FILE,
1193 "Failed to create end session message",
1194 status);
1195 return;
1196 }
1197
Benny Prijonofccab712006-02-22 22:23:22 +00001198 /* pjsip_inv_end_session may return PJ_SUCCESS with NULL
1199 * as p_tdata when INVITE transaction has not been answered
1200 * with any provisional responses.
1201 */
1202 if (tdata == NULL)
1203 return;
1204
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001205 status = pjsip_inv_send_msg(call->inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001206 if (status != PJ_SUCCESS) {
1207 pjsua_perror(THIS_FILE,
1208 "Failed to send end session message",
1209 status);
1210 return;
1211 }
1212}
1213
1214
1215/*
1216 * Put call on-Hold.
1217 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001218void pjsua_call_set_hold(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001219{
1220 pjmedia_sdp_session *sdp;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001221 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001222 pjsip_tx_data *tdata;
1223 pj_status_t status;
1224
Benny Prijonoa91a0032006-02-26 21:23:45 +00001225 call = &pjsua.calls[call_index];
1226
1227 if (!call->inv) {
1228 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1229 return;
1230 }
1231
1232 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001233 PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
1234 return;
1235 }
1236
Benny Prijonoa91a0032006-02-26 21:23:45 +00001237 status = create_inactive_sdp(call, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001238 if (status != PJ_SUCCESS)
1239 return;
1240
1241 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001242 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001243 if (status != PJ_SUCCESS) {
1244 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1245 return;
1246 }
1247
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001248 status = pjsip_inv_send_msg( call->inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001249 if (status != PJ_SUCCESS) {
1250 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1251 return;
1252 }
1253}
1254
1255
1256/*
1257 * re-INVITE.
1258 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001259void pjsua_call_reinvite(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001260{
1261 pjmedia_sdp_session *sdp;
1262 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001263 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001264 pj_status_t status;
1265
Benny Prijonoa91a0032006-02-26 21:23:45 +00001266 call = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +00001267
Benny Prijonoa91a0032006-02-26 21:23:45 +00001268 if (!call->inv) {
1269 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1270 return;
1271 }
1272
1273
1274 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001275 PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
1276 return;
1277 }
1278
1279 /* Create SDP */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001280 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
1281 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001282 if (status != PJ_SUCCESS) {
Benny Prijonoa91a0032006-02-26 21:23:45 +00001283 pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",
1284 status);
Benny Prijono26ff9062006-02-21 23:47:00 +00001285 return;
1286 }
1287
1288 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001289 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001290 if (status != PJ_SUCCESS) {
1291 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1292 return;
1293 }
1294
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001295 status = pjsip_inv_send_msg( call->inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001296 if (status != PJ_SUCCESS) {
1297 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1298 return;
1299 }
1300}
1301
1302
1303/*
1304 * Transfer call.
1305 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001306void pjsua_call_xfer(int call_index, const char *dest)
Benny Prijono26ff9062006-02-21 23:47:00 +00001307{
1308 pjsip_evsub *sub;
1309 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001310 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001311 pj_str_t tmp;
1312 pj_status_t status;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001313
Benny Prijono26ff9062006-02-21 23:47:00 +00001314
Benny Prijonoa91a0032006-02-26 21:23:45 +00001315 call = &pjsua.calls[call_index];
1316
1317 if (!call->inv) {
1318 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1319 return;
1320 }
1321
Benny Prijono26ff9062006-02-21 23:47:00 +00001322 /* Create xfer client subscription.
1323 * We're not interested in knowing the transfer result, so we
1324 * put NULL as the callback.
1325 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001326 status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub);
Benny Prijono26ff9062006-02-21 23:47:00 +00001327 if (status != PJ_SUCCESS) {
1328 pjsua_perror(THIS_FILE, "Unable to create xfer", status);
1329 return;
1330 }
1331
1332 /*
1333 * Create REFER request.
1334 */
1335 status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
1336 if (status != PJ_SUCCESS) {
1337 pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
1338 return;
1339 }
1340
1341 /* Send. */
1342 status = pjsip_xfer_send_request(sub, tdata);
1343 if (status != PJ_SUCCESS) {
1344 pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
1345 return;
1346 }
1347
1348 /* For simplicity (that's what this program is intended to be!),
1349 * leave the original invite session as it is. More advanced application
1350 * may want to hold the INVITE, or terminate the invite, or whatever.
1351 */
Benny Prijono84126ab2006-02-09 09:30:09 +00001352}
Benny Prijono834aee32006-02-19 01:38:06 +00001353
1354
Benny Prijonob0808372006-03-02 21:18:58 +00001355/**
1356 * Send instant messaging inside INVITE session.
1357 */
1358void pjsua_call_send_im(int call_index, const char *str)
1359{
1360 pjsua_call *call;
1361 const pj_str_t mime_text = pj_str("text");
1362 const pj_str_t mime_plain = pj_str("plain");
1363 pj_str_t text;
1364 pjsip_tx_data *tdata;
1365 pj_status_t status;
1366
1367 call = &pjsua.calls[call_index];
1368
1369 if (!call->inv) {
1370 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1371 return;
1372 }
1373
1374 /* Lock dialog. */
1375 pjsip_dlg_inc_lock(call->inv->dlg);
1376
1377 /* Create request message. */
1378 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1379 -1, &tdata);
1380 if (status != PJ_SUCCESS) {
1381 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1382 goto on_return;
1383 }
1384
1385 /* Add accept header. */
1386 pjsip_msg_add_hdr( tdata->msg,
1387 (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
1388
1389 /* Create "text/plain" message body. */
1390 tdata->msg->body = pjsip_msg_body_create( tdata->pool, &mime_text,
1391 &mime_plain,
1392 pj_cstr(&text, str));
1393 if (tdata->msg->body == NULL) {
1394 pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM);
1395 pjsip_tx_data_dec_ref(tdata);
1396 goto on_return;
1397 }
1398
1399 /* Send the request. */
Benny Prijono64158af2006-04-04 11:06:34 +00001400 status = pjsip_dlg_send_request( call->inv->dlg, tdata, -1, NULL);
Benny Prijonob0808372006-03-02 21:18:58 +00001401 if (status != PJ_SUCCESS) {
1402 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1403 goto on_return;
1404 }
1405
1406on_return:
1407 pjsip_dlg_dec_lock(call->inv->dlg);
1408}
1409
1410
1411/**
1412 * Send IM typing indication inside INVITE session.
1413 */
1414void pjsua_call_typing(int call_index, pj_bool_t is_typing)
1415{
1416 pjsua_call *call;
1417 pjsip_tx_data *tdata;
1418 pj_status_t status;
1419
1420 call = &pjsua.calls[call_index];
1421
1422 if (!call->inv) {
1423 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1424 return;
1425 }
1426
1427 /* Lock dialog. */
1428 pjsip_dlg_inc_lock(call->inv->dlg);
1429
1430 /* Create request message. */
1431 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1432 -1, &tdata);
1433 if (status != PJ_SUCCESS) {
1434 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1435 goto on_return;
1436 }
1437
1438 /* Create "application/im-iscomposing+xml" msg body. */
1439 tdata->msg->body = pjsip_iscomposing_create_body(tdata->pool, is_typing,
1440 NULL, NULL, -1);
1441
1442 /* Send the request. */
Benny Prijono64158af2006-04-04 11:06:34 +00001443 status = pjsip_dlg_send_request( call->inv->dlg, tdata, -1, NULL);
Benny Prijonob0808372006-03-02 21:18:58 +00001444 if (status != PJ_SUCCESS) {
1445 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1446 goto on_return;
1447 }
1448
1449on_return:
1450 pjsip_dlg_dec_lock(call->inv->dlg);}
1451
1452
Benny Prijono834aee32006-02-19 01:38:06 +00001453/*
1454 * Terminate all calls.
1455 */
Benny Prijono1c2bf462006-03-05 11:54:02 +00001456void pjsua_call_hangup_all(void)
Benny Prijono834aee32006-02-19 01:38:06 +00001457{
Benny Prijonoa91a0032006-02-26 21:23:45 +00001458 int i;
Benny Prijono834aee32006-02-19 01:38:06 +00001459
Benny Prijonoa91a0032006-02-26 21:23:45 +00001460 for (i=0; i<pjsua.max_calls; ++i) {
Benny Prijono834aee32006-02-19 01:38:06 +00001461 pjsip_tx_data *tdata;
Benny Prijono1c2bf462006-03-05 11:54:02 +00001462 int st_code;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001463 pjsua_call *call;
Benny Prijono834aee32006-02-19 01:38:06 +00001464
Benny Prijonoa91a0032006-02-26 21:23:45 +00001465 if (pjsua.calls[i].inv == NULL)
1466 continue;
Benny Prijono834aee32006-02-19 01:38:06 +00001467
Benny Prijonoa91a0032006-02-26 21:23:45 +00001468 call = &pjsua.calls[i];
1469
Benny Prijono1c2bf462006-03-05 11:54:02 +00001470 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
1471 st_code = 200;
1472 } else {
1473 st_code = PJSIP_SC_GONE;
1474 }
1475
1476 if (pjsip_inv_end_session(call->inv, st_code, NULL, &tdata)==0) {
Benny Prijonofccab712006-02-22 22:23:22 +00001477 if (tdata)
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001478 pjsip_inv_send_msg(call->inv, tdata);
Benny Prijonofccab712006-02-22 22:23:22 +00001479 }
Benny Prijono834aee32006-02-19 01:38:06 +00001480 }
1481}
1482
Benny Prijono26ff9062006-02-21 23:47:00 +00001483
Benny Prijonoa91a0032006-02-26 21:23:45 +00001484pj_status_t pjsua_call_init(void)
1485{
1486 /* Initialize invite session callback. */
1487 pjsip_inv_callback inv_cb;
1488 pj_status_t status;
1489
1490 pj_memset(&inv_cb, 0, sizeof(inv_cb));
1491 inv_cb.on_state_changed = &pjsua_call_on_state_changed;
1492 inv_cb.on_new_session = &pjsua_call_on_forked;
1493 inv_cb.on_media_update = &pjsua_call_on_media_update;
1494 inv_cb.on_rx_offer = &pjsua_call_on_rx_offer;
1495 inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed;
1496
1497
1498 /* Initialize invite session module: */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001499 status = pjsip_inv_usage_init(pjsua.endpt, &inv_cb);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001500
1501 return status;
1502}