blob: d18a59da517458d984b1f7f080cfcfbc3d0b59f4 [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 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
156 }
157
158 PJ_LOG(3,(THIS_FILE, "Media session for call %d is destroyed",
159 call_index));
160
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 Prijono84126ab2006-02-09 09:30:09 +0000195 /* Create outgoing dialog: */
196
Benny Prijonoa91a0032006-02-26 21:23:45 +0000197 status = pjsip_dlg_create_uac( pjsip_ua_instance(),
198 &pjsua.acc[acc_index].local_uri,
199 &pjsua.acc[acc_index].contact_uri,
200 &dest_uri, &dest_uri,
Benny Prijono84126ab2006-02-09 09:30:09 +0000201 &dlg);
202 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000203 pjsua_perror(THIS_FILE, "Dialog creation failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000204 return status;
205 }
206
207 /* Get media capability from media endpoint: */
208
Benny Prijonoa91a0032006-02-26 21:23:45 +0000209 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 1,
210 &pjsua.calls[call_index].skinfo,
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000211 &offer);
Benny Prijono84126ab2006-02-09 09:30:09 +0000212 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000213 pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000214 goto on_error;
215 }
216
217 /* Create the INVITE session: */
218
219 status = pjsip_inv_create_uac( dlg, offer, 0, &inv);
220 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000221 pjsua_perror(THIS_FILE, "Invite session creation failed", status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000222 goto on_error;
223 }
224
225
226 /* Create and associate our data in the session. */
227
Benny Prijonoa91a0032006-02-26 21:23:45 +0000228 pjsua.calls[call_index].inv = inv;
229
230 dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
231 inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
Benny Prijono84126ab2006-02-09 09:30:09 +0000232
233
234 /* Set dialog Route-Set: */
235
Benny Prijonoa91a0032006-02-26 21:23:45 +0000236 if (!pj_list_empty(&pjsua.acc[acc_index].route_set))
237 pjsip_dlg_set_route_set(dlg, &pjsua.acc[acc_index].route_set);
Benny Prijono84126ab2006-02-09 09:30:09 +0000238
239
240 /* Set credentials: */
241
242 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,
243 pjsua.cred_info);
244
245
246 /* Create initial INVITE: */
247
248 status = pjsip_inv_invite(inv, &tdata);
249 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000250 pjsua_perror(THIS_FILE, "Unable to create initial INVITE request",
251 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000252 goto on_error;
253 }
254
255
256 /* Send initial INVITE: */
257
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000258 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono84126ab2006-02-09 09:30:09 +0000259 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000260 pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",
261 status);
Benny Prijono84126ab2006-02-09 09:30:09 +0000262 goto on_error;
263 }
264
265
266 /* Done. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000267
268 ++pjsua.call_cnt;
269
270 if (p_call_index)
271 *p_call_index = call_index;
Benny Prijono84126ab2006-02-09 09:30:09 +0000272
273 return PJ_SUCCESS;
274
275
276on_error:
Benny Prijono1c2bf462006-03-05 11:54:02 +0000277 if (inv != NULL) {
278 pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE);
279 } else {
280 pjsip_dlg_terminate(dlg);
281 }
282
Benny Prijonoa91a0032006-02-26 21:23:45 +0000283 if (call_index != -1) {
284 pjsua.calls[call_index].inv = NULL;
285 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000286 return status;
287}
288
289
290/**
291 * Handle incoming INVITE request.
292 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000293pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
Benny Prijono84126ab2006-02-09 09:30:09 +0000294{
295 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
296 pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
297 pjsip_msg *msg = rdata->msg_info.msg;
Benny Prijono26ff9062006-02-21 23:47:00 +0000298 pjsip_tx_data *response = NULL;
299 unsigned options = 0;
Benny Prijono1c2bf462006-03-05 11:54:02 +0000300 pjsip_inv_session *inv = NULL;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000301 int acc_index;
302 int call_index = -1;
Benny Prijono26ff9062006-02-21 23:47:00 +0000303 pjmedia_sdp_session *answer;
Benny Prijono26ff9062006-02-21 23:47:00 +0000304 pj_status_t status;
Benny Prijono84126ab2006-02-09 09:30:09 +0000305
Benny Prijono26ff9062006-02-21 23:47:00 +0000306 /* Don't want to handle anything but INVITE */
307 if (msg->line.req.method.id != PJSIP_INVITE_METHOD)
308 return PJ_FALSE;
309
310 /* Don't want to handle anything that's already associated with
311 * existing dialog or transaction.
Benny Prijono84126ab2006-02-09 09:30:09 +0000312 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000313 if (dlg || tsx)
314 return PJ_FALSE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000315
Benny Prijono84126ab2006-02-09 09:30:09 +0000316
Benny Prijono26ff9062006-02-21 23:47:00 +0000317 /* Verify that we can handle the request. */
318 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
319 pjsua.endpt, &response);
320 if (status != PJ_SUCCESS) {
Benny Prijono84126ab2006-02-09 09:30:09 +0000321
Benny Prijono26ff9062006-02-21 23:47:00 +0000322 /*
323 * No we can't handle the incoming INVITE request.
324 */
Benny Prijono84126ab2006-02-09 09:30:09 +0000325
Benny Prijono26ff9062006-02-21 23:47:00 +0000326 if (response) {
327 pjsip_response_addr res_addr;
Benny Prijono84126ab2006-02-09 09:30:09 +0000328
Benny Prijono26ff9062006-02-21 23:47:00 +0000329 pjsip_get_response_addr(response->pool, rdata, &res_addr);
330 pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,
331 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000332
333 } else {
Benny Prijono84126ab2006-02-09 09:30:09 +0000334
Benny Prijono26ff9062006-02-21 23:47:00 +0000335 /* Respond with 500 (Internal Server Error) */
336 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
337 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000338 }
339
Benny Prijono26ff9062006-02-21 23:47:00 +0000340 return PJ_TRUE;
341 }
342
343
344 /*
345 * Yes we can handle the incoming INVITE request.
346 */
347
348 /* Find free call slot. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000349 for (call_index=0; call_index < pjsua.max_calls; ++call_index) {
350 if (pjsua.calls[call_index].inv == NULL)
Benny Prijono26ff9062006-02-21 23:47:00 +0000351 break;
352 }
353
Benny Prijonoa91a0032006-02-26 21:23:45 +0000354 if (call_index == PJSUA_MAX_CALLS) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000355 pjsip_endpt_respond_stateless(pjsua.endpt, rdata,
356 PJSIP_SC_BUSY_HERE, NULL,
357 NULL, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000358 return PJ_TRUE;
359 }
360
Benny Prijono26ff9062006-02-21 23:47:00 +0000361
Benny Prijono26ff9062006-02-21 23:47:00 +0000362 /* Get media capability from media endpoint: */
363
Benny Prijonoa91a0032006-02-26 21:23:45 +0000364 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 1,
365 &pjsua.calls[call_index].skinfo,
Benny Prijono26ff9062006-02-21 23:47:00 +0000366 &answer );
367 if (status != PJ_SUCCESS) {
368 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
369 NULL, NULL);
370
Benny Prijono26ff9062006-02-21 23:47:00 +0000371 return PJ_TRUE;
372 }
373
Benny Prijonoa91a0032006-02-26 21:23:45 +0000374 /* TODO:
375 *
376 * Get which account is most likely to be associated with this incoming
377 * call. We need the account to find which contact URI to put for
378 * the call.
379 */
380 acc_index = 0;
381
Benny Prijono26ff9062006-02-21 23:47:00 +0000382 /* Create dialog: */
383
384 status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000385 &pjsua.acc[acc_index].contact_uri,
386 &dlg);
Benny Prijono26ff9062006-02-21 23:47:00 +0000387 if (status != PJ_SUCCESS) {
388 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
389 NULL, NULL);
390
Benny Prijono26ff9062006-02-21 23:47:00 +0000391 return PJ_TRUE;
392 }
393
394
395 /* Create invite session: */
396
397 status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
398 if (status != PJ_SUCCESS) {
399
Benny Prijonob0808372006-03-02 21:18:58 +0000400 pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000401 pjsip_dlg_terminate(dlg);
Benny Prijono26ff9062006-02-21 23:47:00 +0000402 return PJ_TRUE;
403 }
404
405
406 /* Create and attach pjsua data to the dialog: */
407
Benny Prijonoa91a0032006-02-26 21:23:45 +0000408 pjsua.calls[call_index].inv = inv;
Benny Prijono26ff9062006-02-21 23:47:00 +0000409
Benny Prijonoa91a0032006-02-26 21:23:45 +0000410 dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
411 inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +0000412
413
Benny Prijono64f851e2006-02-23 13:49:28 +0000414 /* Must answer with some response to initial INVITE.
415 * If auto-answer flag is set, send 200 straight away, otherwise send 100.
416 */
417
418 status = pjsip_inv_initial_answer(inv, rdata,
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000419 (pjsua.auto_answer ? pjsua.auto_answer
420 : 100),
Benny Prijono64f851e2006-02-23 13:49:28 +0000421 NULL, NULL, &response);
Benny Prijono26ff9062006-02-21 23:47:00 +0000422 if (status != PJ_SUCCESS) {
423
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000424 int st_code;
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000425
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000426 pjsua_perror(THIS_FILE, "Unable to send answer to incoming INVITE",
427 status);
428
429 /* If failed to send 2xx response, there's a good chance that it is
430 * because SDP negotiation has failed.
431 */
432 if (pjsua.auto_answer/100 == 2)
433 st_code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
434 else
435 st_code = 500;
436
437 pjsip_dlg_respond(dlg, rdata, st_code, NULL, NULL, NULL);
438 pjsip_inv_terminate(inv, st_code, PJ_FALSE);
439 return PJ_TRUE;
Benny Prijono26ff9062006-02-21 23:47:00 +0000440
441 } else {
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000442 status = pjsip_inv_send_msg(inv, response);
Benny Prijonod2ae29d2006-02-22 15:42:31 +0000443 if (status != PJ_SUCCESS)
444 pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
Benny Prijono26ff9062006-02-21 23:47:00 +0000445 }
446
Benny Prijono64f851e2006-02-23 13:49:28 +0000447 if (pjsua.auto_answer < 200) {
448 PJ_LOG(3,(THIS_FILE,
449 "\nIncoming call!!\n"
450 "From: %.*s\n"
451 "To: %.*s\n"
452 "(press 'a' to answer, 'h' to decline)",
453 (int)dlg->remote.info_str.slen,
454 dlg->remote.info_str.ptr,
455 (int)dlg->local.info_str.slen,
456 dlg->local.info_str.ptr));
457 } else {
458 PJ_LOG(3,(THIS_FILE,
459 "Call From:%.*s To:%.*s was answered with %d (%s)",
460 (int)dlg->remote.info_str.slen,
461 dlg->remote.info_str.ptr,
462 (int)dlg->local.info_str.slen,
463 dlg->local.info_str.ptr,
464 pjsua.auto_answer,
465 pjsip_get_status_text(pjsua.auto_answer)->ptr ));
466 }
467
Benny Prijonoa91a0032006-02-26 21:23:45 +0000468 ++pjsua.call_cnt;
469
Benny Prijono105217f2006-03-06 16:25:59 +0000470 /* Schedule timer to refresh. */
471 if (pjsua.uas_refresh > 0) {
472 schedule_call_timer( &pjsua.calls[call_index],
473 &pjsua.calls[call_index].refresh_tm,
474 REFRESH_CALL_TIMER,
475 pjsua.uas_refresh);
476 }
477
478 /* Schedule timer to hangup call. */
479 if (pjsua.uas_duration > 0) {
480 schedule_call_timer( &pjsua.calls[call_index],
481 &pjsua.calls[call_index].hangup_tm,
482 HANGUP_CALL_TIMER,
483 pjsua.uas_duration);
484 }
485
Benny Prijono26ff9062006-02-21 23:47:00 +0000486 /* This INVITE request has been handled. */
487 return PJ_TRUE;
Benny Prijono84126ab2006-02-09 09:30:09 +0000488}
489
490
491/*
492 * This callback receives notification from invite session when the
493 * session state has changed.
494 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000495static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
496 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000497{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000498 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000499
500 /* If this is an outgoing INVITE that was created because of
501 * REFER/transfer, send NOTIFY to transferer.
502 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000503 if (call && call->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000504 int st_code = -1;
505 pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
506
507
Benny Prijonoa91a0032006-02-26 21:23:45 +0000508 switch (call->inv->state) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000509 case PJSIP_INV_STATE_NULL:
510 case PJSIP_INV_STATE_CALLING:
511 /* Do nothing */
512 break;
513
514 case PJSIP_INV_STATE_EARLY:
515 case PJSIP_INV_STATE_CONNECTING:
516 st_code = e->body.tsx_state.tsx->status_code;
517 ev_state = PJSIP_EVSUB_STATE_ACTIVE;
518 break;
519
520 case PJSIP_INV_STATE_CONFIRMED:
521 /* When state is confirmed, send the final 200/OK and terminate
522 * subscription.
523 */
524 st_code = e->body.tsx_state.tsx->status_code;
525 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
526 break;
527
528 case PJSIP_INV_STATE_DISCONNECTED:
529 st_code = e->body.tsx_state.tsx->status_code;
530 ev_state = PJSIP_EVSUB_STATE_TERMINATED;
531 break;
532 }
533
534 if (st_code != -1) {
535 pjsip_tx_data *tdata;
536 pj_status_t status;
537
Benny Prijonoa91a0032006-02-26 21:23:45 +0000538 status = pjsip_xfer_notify( call->xfer_sub,
Benny Prijono26ff9062006-02-21 23:47:00 +0000539 ev_state, st_code,
540 NULL, &tdata);
541 if (status != PJ_SUCCESS) {
542 pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);
543 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000544 status = pjsip_xfer_send_request(call->xfer_sub, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +0000545 if (status != PJ_SUCCESS) {
546 pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);
547 }
548 }
549 }
550 }
551
Benny Prijono84126ab2006-02-09 09:30:09 +0000552
Benny Prijonob0808372006-03-02 21:18:58 +0000553 pjsua_ui_on_call_state(call->index, e);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000554
555 /* call->inv may be NULL now */
556
Benny Prijono84126ab2006-02-09 09:30:09 +0000557 /* Destroy media session when invite session is disconnected. */
558 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono632ce712006-02-09 14:01:40 +0000559
Benny Prijonoa91a0032006-02-26 21:23:45 +0000560 pj_assert(call != NULL);
Benny Prijono632ce712006-02-09 14:01:40 +0000561
Benny Prijono275fd682006-03-22 11:59:11 +0000562 if (call)
563 call_destroy_media(call->index);
Benny Prijono84126ab2006-02-09 09:30:09 +0000564
Benny Prijono105217f2006-03-06 16:25:59 +0000565 /* Remove timers. */
566 schedule_call_timer(call, &call->refresh_tm, REFRESH_CALL_TIMER, 0);
567 schedule_call_timer(call, &call->hangup_tm, HANGUP_CALL_TIMER, 0);
568
569 /* Free call */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000570 call->inv = NULL;
571 --pjsua.call_cnt;
Benny Prijono84126ab2006-02-09 09:30:09 +0000572 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000573}
574
575
576/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000577 * Callback called by event framework when the xfer subscription state
578 * has changed.
579 */
580static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
581{
582
583 PJ_UNUSED_ARG(event);
584
585 /*
586 * We're only interested when subscription is terminated, to
587 * clear the xfer_sub member of the inv_data.
588 */
589 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000590 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000591
Benny Prijonoa91a0032006-02-26 21:23:45 +0000592 call = pjsip_evsub_get_mod_data(sub, pjsua.mod.id);
593 if (!call)
Benny Prijono26ff9062006-02-21 23:47:00 +0000594 return;
595
596 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000597 call->xfer_sub = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +0000598
599 PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated"));
600 }
601}
602
603
604/*
605 * Follow transfer (REFER) request.
606 */
607static void on_call_transfered( pjsip_inv_session *inv,
608 pjsip_rx_data *rdata )
609{
610 pj_status_t status;
611 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000612 pjsua_call *existing_call;
613 int new_call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000614 const pj_str_t str_refer_to = { "Refer-To", 8};
615 pjsip_generic_string_hdr *refer_to;
616 char *uri;
617 struct pjsip_evsub_user xfer_cb;
618 pjsip_evsub *sub;
619
Benny Prijonoa91a0032006-02-26 21:23:45 +0000620 existing_call = inv->dlg->mod_data[pjsua.mod.id];
621
Benny Prijono26ff9062006-02-21 23:47:00 +0000622 /* Find the Refer-To header */
623 refer_to = (pjsip_generic_string_hdr*)
624 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
625
626 if (refer_to == NULL) {
627 /* Invalid Request.
628 * No Refer-To header!
629 */
630 PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!"));
Benny Prijonob0808372006-03-02 21:18:58 +0000631 pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000632 return;
633 }
634
635 PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s",
636 (int)inv->dlg->remote.info_str.slen,
637 inv->dlg->remote.info_str.ptr,
638 (int)refer_to->hvalue.slen,
639 refer_to->hvalue.ptr));
640
641 /* Init callback */
642 pj_memset(&xfer_cb, 0, sizeof(xfer_cb));
643 xfer_cb.on_evsub_state = &xfer_on_evsub_state;
644
645 /* Create transferee event subscription */
646 status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
647 if (status != PJ_SUCCESS) {
648 pjsua_perror(THIS_FILE, "Unable to create xfer uas", status);
Benny Prijonob0808372006-03-02 21:18:58 +0000649 pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
Benny Prijono26ff9062006-02-21 23:47:00 +0000650 return;
651 }
652
653 /* Accept the REFER request, send 200 (OK). */
654 pjsip_xfer_accept(sub, rdata, 200, NULL);
655
656 /* Create initial NOTIFY request */
657 status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
658 100, NULL, &tdata);
659 if (status != PJ_SUCCESS) {
660 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status);
661 return;
662 }
663
664 /* Send initial NOTIFY request */
665 status = pjsip_xfer_send_request( sub, tdata);
666 if (status != PJ_SUCCESS) {
667 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status);
668 return;
669 }
670
671 /* We're cheating here.
672 * We need to get a null terminated string from a pj_str_t.
673 * So grab the pointer from the hvalue and NULL terminate it, knowing
674 * that the NULL position will be occupied by a newline.
675 */
676 uri = refer_to->hvalue.ptr;
677 uri[refer_to->hvalue.slen] = '\0';
678
679 /* Now make the outgoing call. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000680 status = pjsua_make_call(existing_call->acc_index, uri, &new_call);
Benny Prijono26ff9062006-02-21 23:47:00 +0000681 if (status != PJ_SUCCESS) {
682
683 /* Notify xferer about the error */
684 status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
685 500, NULL, &tdata);
686 if (status != PJ_SUCCESS) {
687 pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",
688 status);
689 return;
690 }
691 status = pjsip_xfer_send_request(sub, tdata);
692 if (status != PJ_SUCCESS) {
693 pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",
694 status);
695 return;
696 }
697 return;
698 }
699
700 /* Put the server subscription in inv_data.
701 * Subsequent state changed in pjsua_inv_on_state_changed() will be
702 * reported back to the server subscription.
703 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000704 pjsua.calls[new_call].xfer_sub = sub;
Benny Prijono26ff9062006-02-21 23:47:00 +0000705
706 /* Put the invite_data in the subscription. */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000707 pjsip_evsub_set_mod_data(sub, pjsua.mod.id, &pjsua.calls[new_call]);
Benny Prijono26ff9062006-02-21 23:47:00 +0000708}
709
710
711/*
712 * This callback is called when transaction state has changed in INVITE
Benny Prijonob0808372006-03-02 21:18:58 +0000713 * session. We use this to trap:
714 * - incoming REFER request.
715 * - incoming MESSAGE request.
Benny Prijono26ff9062006-02-21 23:47:00 +0000716 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000717static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
718 pjsip_transaction *tsx,
719 pjsip_event *e)
Benny Prijono26ff9062006-02-21 23:47:00 +0000720{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000721 pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id];
722
Benny Prijono26ff9062006-02-21 23:47:00 +0000723 if (tsx->role==PJSIP_ROLE_UAS &&
724 tsx->state==PJSIP_TSX_STATE_TRYING &&
725 pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0)
726 {
727 /*
728 * Incoming REFER request.
729 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000730 on_call_transfered(call->inv, e->body.tsx_state.src.rdata);
Benny Prijonob0808372006-03-02 21:18:58 +0000731
Benny Prijono26ff9062006-02-21 23:47:00 +0000732 }
Benny Prijonob0808372006-03-02 21:18:58 +0000733 else if (tsx->role==PJSIP_ROLE_UAS &&
734 tsx->state==PJSIP_TSX_STATE_TRYING &&
735 pjsip_method_cmp(&tsx->method, &pjsip_message_method)==0)
736 {
737 /*
738 * Incoming MESSAGE request!
739 */
740 pjsip_rx_data *rdata;
741 pjsip_msg *msg;
742 pjsip_accept_hdr *accept_hdr;
743 pj_status_t status;
744
745 rdata = e->body.tsx_state.src.rdata;
746 msg = rdata->msg_info.msg;
747
748 /* Request MUST have message body, with Content-Type equal to
749 * "text/plain".
750 */
751 if (pjsua_im_accept_pager(rdata, &accept_hdr) == PJ_FALSE) {
752
753 pjsip_hdr hdr_list;
754
755 pj_list_init(&hdr_list);
756 pj_list_push_back(&hdr_list, accept_hdr);
757
758 pjsip_dlg_respond( inv->dlg, rdata, PJSIP_SC_NOT_ACCEPTABLE_HERE,
759 NULL, &hdr_list, NULL );
760 return;
761 }
762
763 /* Respond with 200 first, so that remote doesn't retransmit in case
764 * the UI takes too long to process the message.
765 */
766 status = pjsip_dlg_respond( inv->dlg, rdata, 200, NULL, NULL, NULL);
767
768 /* Process MESSAGE request */
769 pjsua_im_process_pager(call->index, &inv->dlg->remote.info_str,
770 &inv->dlg->local.info_str, rdata);
771 }
772
Benny Prijono26ff9062006-02-21 23:47:00 +0000773}
774
775
776/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000777 * This callback is called by invite session framework when UAC session
778 * has forked.
779 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000780static void pjsua_call_on_forked( pjsip_inv_session *inv,
781 pjsip_event *e)
Benny Prijono84126ab2006-02-09 09:30:09 +0000782{
783 PJ_UNUSED_ARG(inv);
784 PJ_UNUSED_ARG(e);
785
786 PJ_TODO(HANDLE_FORKED_DIALOG);
787}
788
789
790/*
Benny Prijono26ff9062006-02-21 23:47:00 +0000791 * Create inactive SDP for call hold.
792 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000793static pj_status_t create_inactive_sdp(pjsua_call *call,
Benny Prijono26ff9062006-02-21 23:47:00 +0000794 pjmedia_sdp_session **p_answer)
795{
796 pj_status_t status;
797 pjmedia_sdp_conn *conn;
798 pjmedia_sdp_attr *attr;
799 pjmedia_sdp_session *sdp;
800
801 /* Create new offer */
802 status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000803 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +0000804 if (status != PJ_SUCCESS) {
805 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
806 return status;
807 }
808
809 /* Get SDP media connection line */
810 conn = sdp->media[0]->conn;
811 if (!conn)
812 conn = sdp->conn;
813
814 /* Modify address */
815 conn->addr = pj_str("0.0.0.0");
816
817 /* Remove existing directions attributes */
818 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
819 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
820 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
821 pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
822
823 /* Add inactive attribute */
824 attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL);
825 pjmedia_sdp_media_add_attr(sdp->media[0], attr);
826
827 *p_answer = sdp;
828
829 return status;
830}
831
832/*
833 * Called when session received new offer.
834 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000835static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
836 const pjmedia_sdp_session *offer)
Benny Prijono26ff9062006-02-21 23:47:00 +0000837{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000838 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +0000839 pjmedia_sdp_conn *conn;
840 pjmedia_sdp_session *answer;
841 pj_bool_t is_remote_active;
842 pj_status_t status;
843
Benny Prijonoa91a0032006-02-26 21:23:45 +0000844 call = inv->dlg->mod_data[pjsua.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +0000845
846 /*
847 * See if remote is offering active media (i.e. not on-hold)
848 */
849 is_remote_active = PJ_TRUE;
850
851 conn = offer->media[0]->conn;
852 if (!conn)
853 conn = offer->conn;
854
855 if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
856 pj_strcmp2(&conn->addr, "0")==0)
857 {
858 is_remote_active = PJ_FALSE;
859
860 }
861 else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))
862 {
863 is_remote_active = PJ_FALSE;
864 }
865
866 PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s",
867 (is_remote_active ? "active" : "inactive")));
868
869 /* Supply candidate answer */
870 if (is_remote_active) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000871 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
872 &call->skinfo, &answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000873 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000874 status = create_inactive_sdp( call, &answer );
Benny Prijono26ff9062006-02-21 23:47:00 +0000875 }
876
877 if (status != PJ_SUCCESS) {
878 pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
879 return;
880 }
881
Benny Prijonoa91a0032006-02-26 21:23:45 +0000882 status = pjsip_inv_set_sdp_answer(call->inv, answer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000883 if (status != PJ_SUCCESS) {
884 pjsua_perror(THIS_FILE, "Unable to set answer", status);
885 return;
886 }
887
888}
889
Benny Prijono1c2bf462006-03-05 11:54:02 +0000890/* Disconnect call */
891static void call_disconnect(pjsip_inv_session *inv,
892 int st_code)
893{
894 pjsip_tx_data *tdata;
895 pj_status_t status;
896
897 status = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
898 if (status == PJ_SUCCESS)
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000899 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000900
901 if (status != PJ_SUCCESS) {
902 pjsua_perror(THIS_FILE, "Unable to disconnect call", status);
903 }
904}
Benny Prijono26ff9062006-02-21 23:47:00 +0000905
906/*
Benny Prijono84126ab2006-02-09 09:30:09 +0000907 * Callback to be called when SDP offer/answer negotiation has just completed
908 * in the session. This function will start/update media if negotiation
909 * has succeeded.
910 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000911static void pjsua_call_on_media_update(pjsip_inv_session *inv,
912 pj_status_t status)
Benny Prijono84126ab2006-02-09 09:30:09 +0000913{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000914 pjsua_call *call;
Benny Prijono84126ab2006-02-09 09:30:09 +0000915 const pjmedia_sdp_session *local_sdp;
916 const pjmedia_sdp_session *remote_sdp;
Benny Prijono26ff9062006-02-21 23:47:00 +0000917 pjmedia_port *media_port;
918 pj_str_t port_name;
919 char tmp[PJSIP_MAX_URL_SIZE];
Benny Prijono84126ab2006-02-09 09:30:09 +0000920
Benny Prijonoa91a0032006-02-26 21:23:45 +0000921 call = inv->dlg->mod_data[pjsua.mod.id];
922
Benny Prijono84126ab2006-02-09 09:30:09 +0000923 if (status != PJ_SUCCESS) {
924
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000925 pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000926
Benny Prijonoccb03fa2006-03-06 13:35:47 +0000927 /* Disconnect call if we're not in the middle of initializing an
928 * UAS dialog and if this is not a re-INVITE
929 */
930 if (inv->state != PJSIP_INV_STATE_NULL &&
931 inv->state != PJSIP_INV_STATE_CONFIRMED)
932 {
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000933 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000934 }
Benny Prijono84126ab2006-02-09 09:30:09 +0000935 return;
936
937 }
938
939 /* Destroy existing media session, if any. */
940
Benny Prijono275fd682006-03-22 11:59:11 +0000941 if (call)
942 call_destroy_media(call->index);
Benny Prijono84126ab2006-02-09 09:30:09 +0000943
944 /* Get local and remote SDP */
945
Benny Prijonoa91a0032006-02-26 21:23:45 +0000946 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000947 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000948 pjsua_perror(THIS_FILE,
949 "Unable to retrieve currently active local SDP",
950 status);
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000951 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000952 return;
953 }
954
955
Benny Prijonoa91a0032006-02-26 21:23:45 +0000956 status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
Benny Prijono84126ab2006-02-09 09:30:09 +0000957 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000958 pjsua_perror(THIS_FILE,
959 "Unable to retrieve currently active remote SDP",
960 status);
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000961 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono84126ab2006-02-09 09:30:09 +0000962 return;
963 }
964
Benny Prijono84126ab2006-02-09 09:30:09 +0000965 /* Create new media session.
966 * The media session is active immediately.
967 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000968 if (pjsua.null_audio)
969 return;
970
971 status = pjmedia_session_create( pjsua.med_endpt, 1,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000972 &call->skinfo,
Benny Prijono26ff9062006-02-21 23:47:00 +0000973 local_sdp, remote_sdp,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000974 call,
975 &call->session );
Benny Prijono26ff9062006-02-21 23:47:00 +0000976 if (status != PJ_SUCCESS) {
977 pjsua_perror(THIS_FILE, "Unable to create media session",
978 status);
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000979 //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
Benny Prijono26ff9062006-02-21 23:47:00 +0000980 return;
Benny Prijono84126ab2006-02-09 09:30:09 +0000981 }
Benny Prijono26ff9062006-02-21 23:47:00 +0000982
983
984 /* Get the port interface of the first stream in the session.
985 * We need the port interface to add to the conference bridge.
986 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000987 pjmedia_session_get_port(call->session, 0, &media_port);
Benny Prijono26ff9062006-02-21 23:47:00 +0000988
989
990 /*
991 * Add the call to conference bridge.
992 */
993 port_name.ptr = tmp;
994 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
Benny Prijonoa91a0032006-02-26 21:23:45 +0000995 call->inv->dlg->remote.info->uri,
Benny Prijono26ff9062006-02-21 23:47:00 +0000996 tmp, sizeof(tmp));
997 if (port_name.slen < 1) {
998 port_name = pj_str("call");
999 }
Benny Prijonoa91a0032006-02-26 21:23:45 +00001000 status = pjmedia_conf_add_port( pjsua.mconf, call->inv->pool,
Benny Prijono26ff9062006-02-21 23:47:00 +00001001 media_port,
1002 &port_name,
Benny Prijonoa91a0032006-02-26 21:23:45 +00001003 &call->conf_slot);
Benny Prijono26ff9062006-02-21 23:47:00 +00001004 if (status != PJ_SUCCESS) {
1005 pjsua_perror(THIS_FILE, "Unable to create conference slot",
1006 status);
Benny Prijono275fd682006-03-22 11:59:11 +00001007 call_destroy_media(call->index);
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001008 //call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR);
Benny Prijono26ff9062006-02-21 23:47:00 +00001009 return;
1010 }
1011
Benny Prijono64f851e2006-02-23 13:49:28 +00001012 /* If auto-play is configured, connect the call to the file player
1013 * port
Benny Prijono26ff9062006-02-21 23:47:00 +00001014 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001015 if (pjsua.auto_play && pjsua.wav_file &&
1016 call->inv->role == PJSIP_ROLE_UAS)
1017 {
Benny Prijono64f851e2006-02-23 13:49:28 +00001018
1019 pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,
Benny Prijonob100d692006-03-17 00:16:01 +00001020 call->conf_slot, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001021
1022 } else if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) {
1023
1024 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
Benny Prijonob100d692006-03-17 00:16:01 +00001025 call->conf_slot, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001026
1027 } else if (pjsua.auto_conf) {
1028
1029 int i;
1030
Benny Prijonob100d692006-03-17 00:16:01 +00001031 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0);
1032 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001033
1034 for (i=0; i < pjsua.max_calls; ++i) {
1035
1036 if (!pjsua.calls[i].session)
1037 continue;
1038
1039 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,
Benny Prijonob100d692006-03-17 00:16:01 +00001040 pjsua.calls[i].conf_slot, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001041 pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot,
Benny Prijonob100d692006-03-17 00:16:01 +00001042 call->conf_slot, 0);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001043 }
Benny Prijono64f851e2006-02-23 13:49:28 +00001044
1045 } else {
1046
1047 /* Connect new call to the sound device port (port zero) in the
1048 * main conference bridge.
1049 */
Benny Prijonob100d692006-03-17 00:16:01 +00001050 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0);
1051 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0);
Benny Prijono64f851e2006-02-23 13:49:28 +00001052 }
1053
Benny Prijono26ff9062006-02-21 23:47:00 +00001054
1055 /* Done. */
1056 {
1057 struct pjmedia_session_info sess_info;
1058 char info[80];
1059 int info_len = 0;
1060 unsigned i;
1061
Benny Prijonoa91a0032006-02-26 21:23:45 +00001062 pjmedia_session_get_info(call->session, &sess_info);
Benny Prijono26ff9062006-02-21 23:47:00 +00001063 for (i=0; i<sess_info.stream_cnt; ++i) {
1064 int len;
1065 const char *dir;
1066 pjmedia_stream_info *strm_info = &sess_info.stream_info[i];
1067
1068 switch (strm_info->dir) {
1069 case PJMEDIA_DIR_NONE:
1070 dir = "inactive";
1071 break;
1072 case PJMEDIA_DIR_ENCODING:
1073 dir = "sendonly";
1074 break;
1075 case PJMEDIA_DIR_DECODING:
1076 dir = "recvonly";
1077 break;
1078 case PJMEDIA_DIR_ENCODING_DECODING:
1079 dir = "sendrecv";
1080 break;
1081 default:
1082 dir = "unknown";
1083 break;
1084 }
1085 len = pj_ansi_sprintf( info+info_len,
1086 ", stream #%d: %.*s (%s)", i,
1087 (int)strm_info->fmt.encoding_name.slen,
Benny Prijonoab7399b2006-02-27 00:40:31 +00001088 strm_info->fmt.encoding_name.ptr,
Benny Prijono26ff9062006-02-21 23:47:00 +00001089 dir);
1090 if (len > 0)
1091 info_len += len;
1092 }
1093 PJ_LOG(3,(THIS_FILE,"Media started%s", info));
1094 }
1095}
1096
1097
1098/*
1099 * Hangup call.
1100 */
Benny Prijono1c2bf462006-03-05 11:54:02 +00001101void pjsua_call_hangup(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001102{
Benny Prijonoa91a0032006-02-26 21:23:45 +00001103 pjsua_call *call;
Benny Prijono1c2bf462006-03-05 11:54:02 +00001104 int code;
Benny Prijono26ff9062006-02-21 23:47:00 +00001105 pj_status_t status;
1106 pjsip_tx_data *tdata;
1107
Benny Prijonoa91a0032006-02-26 21:23:45 +00001108
1109 call = &pjsua.calls[call_index];
1110
1111 if (!call->inv) {
1112 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1113 return;
1114 }
1115
Benny Prijono1c2bf462006-03-05 11:54:02 +00001116 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
1117 code = PJSIP_SC_OK;
1118 else if (call->inv->role == PJSIP_ROLE_UAS)
1119 code = PJSIP_SC_DECLINE;
1120 else
1121 code = PJSIP_SC_REQUEST_TERMINATED;
1122
Benny Prijonoa91a0032006-02-26 21:23:45 +00001123 status = pjsip_inv_end_session(call->inv, code, NULL, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001124 if (status != PJ_SUCCESS) {
1125 pjsua_perror(THIS_FILE,
1126 "Failed to create end session message",
1127 status);
1128 return;
1129 }
1130
Benny Prijonofccab712006-02-22 22:23:22 +00001131 /* pjsip_inv_end_session may return PJ_SUCCESS with NULL
1132 * as p_tdata when INVITE transaction has not been answered
1133 * with any provisional responses.
1134 */
1135 if (tdata == NULL)
1136 return;
1137
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001138 status = pjsip_inv_send_msg(call->inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001139 if (status != PJ_SUCCESS) {
1140 pjsua_perror(THIS_FILE,
1141 "Failed to send end session message",
1142 status);
1143 return;
1144 }
1145}
1146
1147
1148/*
1149 * Put call on-Hold.
1150 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001151void pjsua_call_set_hold(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001152{
1153 pjmedia_sdp_session *sdp;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001154 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001155 pjsip_tx_data *tdata;
1156 pj_status_t status;
1157
Benny Prijonoa91a0032006-02-26 21:23:45 +00001158 call = &pjsua.calls[call_index];
1159
1160 if (!call->inv) {
1161 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1162 return;
1163 }
1164
1165 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001166 PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
1167 return;
1168 }
1169
Benny Prijonoa91a0032006-02-26 21:23:45 +00001170 status = create_inactive_sdp(call, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001171 if (status != PJ_SUCCESS)
1172 return;
1173
1174 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001175 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001176 if (status != PJ_SUCCESS) {
1177 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1178 return;
1179 }
1180
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001181 status = pjsip_inv_send_msg( call->inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001182 if (status != PJ_SUCCESS) {
1183 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1184 return;
1185 }
1186}
1187
1188
1189/*
1190 * re-INVITE.
1191 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001192void pjsua_call_reinvite(int call_index)
Benny Prijono26ff9062006-02-21 23:47:00 +00001193{
1194 pjmedia_sdp_session *sdp;
1195 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001196 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001197 pj_status_t status;
1198
Benny Prijonoa91a0032006-02-26 21:23:45 +00001199 call = &pjsua.calls[call_index];
Benny Prijono26ff9062006-02-21 23:47:00 +00001200
Benny Prijonoa91a0032006-02-26 21:23:45 +00001201 if (!call->inv) {
1202 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1203 return;
1204 }
1205
1206
1207 if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001208 PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
1209 return;
1210 }
1211
1212 /* Create SDP */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001213 status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1,
1214 &call->skinfo, &sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001215 if (status != PJ_SUCCESS) {
Benny Prijonoa91a0032006-02-26 21:23:45 +00001216 pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",
1217 status);
Benny Prijono26ff9062006-02-21 23:47:00 +00001218 return;
1219 }
1220
1221 /* Send re-INVITE with new offer */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001222 status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001223 if (status != PJ_SUCCESS) {
1224 pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
1225 return;
1226 }
1227
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001228 status = pjsip_inv_send_msg( call->inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00001229 if (status != PJ_SUCCESS) {
1230 pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
1231 return;
1232 }
1233}
1234
1235
1236/*
1237 * Transfer call.
1238 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001239void pjsua_call_xfer(int call_index, const char *dest)
Benny Prijono26ff9062006-02-21 23:47:00 +00001240{
1241 pjsip_evsub *sub;
1242 pjsip_tx_data *tdata;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001243 pjsua_call *call;
Benny Prijono26ff9062006-02-21 23:47:00 +00001244 pj_str_t tmp;
1245 pj_status_t status;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001246
Benny Prijono26ff9062006-02-21 23:47:00 +00001247
Benny Prijonoa91a0032006-02-26 21:23:45 +00001248 call = &pjsua.calls[call_index];
1249
1250 if (!call->inv) {
1251 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1252 return;
1253 }
1254
Benny Prijono26ff9062006-02-21 23:47:00 +00001255 /* Create xfer client subscription.
1256 * We're not interested in knowing the transfer result, so we
1257 * put NULL as the callback.
1258 */
Benny Prijonoa91a0032006-02-26 21:23:45 +00001259 status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub);
Benny Prijono26ff9062006-02-21 23:47:00 +00001260 if (status != PJ_SUCCESS) {
1261 pjsua_perror(THIS_FILE, "Unable to create xfer", status);
1262 return;
1263 }
1264
1265 /*
1266 * Create REFER request.
1267 */
1268 status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata);
1269 if (status != PJ_SUCCESS) {
1270 pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
1271 return;
1272 }
1273
1274 /* Send. */
1275 status = pjsip_xfer_send_request(sub, tdata);
1276 if (status != PJ_SUCCESS) {
1277 pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
1278 return;
1279 }
1280
1281 /* For simplicity (that's what this program is intended to be!),
1282 * leave the original invite session as it is. More advanced application
1283 * may want to hold the INVITE, or terminate the invite, or whatever.
1284 */
Benny Prijono84126ab2006-02-09 09:30:09 +00001285}
Benny Prijono834aee32006-02-19 01:38:06 +00001286
1287
Benny Prijonob0808372006-03-02 21:18:58 +00001288/**
1289 * Send instant messaging inside INVITE session.
1290 */
1291void pjsua_call_send_im(int call_index, const char *str)
1292{
1293 pjsua_call *call;
1294 const pj_str_t mime_text = pj_str("text");
1295 const pj_str_t mime_plain = pj_str("plain");
1296 pj_str_t text;
1297 pjsip_tx_data *tdata;
1298 pj_status_t status;
1299
1300 call = &pjsua.calls[call_index];
1301
1302 if (!call->inv) {
1303 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1304 return;
1305 }
1306
1307 /* Lock dialog. */
1308 pjsip_dlg_inc_lock(call->inv->dlg);
1309
1310 /* Create request message. */
1311 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1312 -1, &tdata);
1313 if (status != PJ_SUCCESS) {
1314 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1315 goto on_return;
1316 }
1317
1318 /* Add accept header. */
1319 pjsip_msg_add_hdr( tdata->msg,
1320 (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
1321
1322 /* Create "text/plain" message body. */
1323 tdata->msg->body = pjsip_msg_body_create( tdata->pool, &mime_text,
1324 &mime_plain,
1325 pj_cstr(&text, str));
1326 if (tdata->msg->body == NULL) {
1327 pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM);
1328 pjsip_tx_data_dec_ref(tdata);
1329 goto on_return;
1330 }
1331
1332 /* Send the request. */
1333 status = pjsip_dlg_send_request( call->inv->dlg, tdata, NULL);
1334 if (status != PJ_SUCCESS) {
1335 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1336 goto on_return;
1337 }
1338
1339on_return:
1340 pjsip_dlg_dec_lock(call->inv->dlg);
1341}
1342
1343
1344/**
1345 * Send IM typing indication inside INVITE session.
1346 */
1347void pjsua_call_typing(int call_index, pj_bool_t is_typing)
1348{
1349 pjsua_call *call;
1350 pjsip_tx_data *tdata;
1351 pj_status_t status;
1352
1353 call = &pjsua.calls[call_index];
1354
1355 if (!call->inv) {
1356 PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
1357 return;
1358 }
1359
1360 /* Lock dialog. */
1361 pjsip_dlg_inc_lock(call->inv->dlg);
1362
1363 /* Create request message. */
1364 status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
1365 -1, &tdata);
1366 if (status != PJ_SUCCESS) {
1367 pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);
1368 goto on_return;
1369 }
1370
1371 /* Create "application/im-iscomposing+xml" msg body. */
1372 tdata->msg->body = pjsip_iscomposing_create_body(tdata->pool, is_typing,
1373 NULL, NULL, -1);
1374
1375 /* Send the request. */
1376 status = pjsip_dlg_send_request( call->inv->dlg, tdata, NULL);
1377 if (status != PJ_SUCCESS) {
1378 pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);
1379 goto on_return;
1380 }
1381
1382on_return:
1383 pjsip_dlg_dec_lock(call->inv->dlg);}
1384
1385
Benny Prijono834aee32006-02-19 01:38:06 +00001386/*
1387 * Terminate all calls.
1388 */
Benny Prijono1c2bf462006-03-05 11:54:02 +00001389void pjsua_call_hangup_all(void)
Benny Prijono834aee32006-02-19 01:38:06 +00001390{
Benny Prijonoa91a0032006-02-26 21:23:45 +00001391 int i;
Benny Prijono834aee32006-02-19 01:38:06 +00001392
Benny Prijonoa91a0032006-02-26 21:23:45 +00001393 for (i=0; i<pjsua.max_calls; ++i) {
Benny Prijono834aee32006-02-19 01:38:06 +00001394 pjsip_tx_data *tdata;
Benny Prijono1c2bf462006-03-05 11:54:02 +00001395 int st_code;
Benny Prijonoa91a0032006-02-26 21:23:45 +00001396 pjsua_call *call;
Benny Prijono834aee32006-02-19 01:38:06 +00001397
Benny Prijonoa91a0032006-02-26 21:23:45 +00001398 if (pjsua.calls[i].inv == NULL)
1399 continue;
Benny Prijono834aee32006-02-19 01:38:06 +00001400
Benny Prijonoa91a0032006-02-26 21:23:45 +00001401 call = &pjsua.calls[i];
1402
Benny Prijono1c2bf462006-03-05 11:54:02 +00001403 if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
1404 st_code = 200;
1405 } else {
1406 st_code = PJSIP_SC_GONE;
1407 }
1408
1409 if (pjsip_inv_end_session(call->inv, st_code, NULL, &tdata)==0) {
Benny Prijonofccab712006-02-22 22:23:22 +00001410 if (tdata)
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001411 pjsip_inv_send_msg(call->inv, tdata);
Benny Prijonofccab712006-02-22 22:23:22 +00001412 }
Benny Prijono834aee32006-02-19 01:38:06 +00001413 }
1414}
1415
Benny Prijono26ff9062006-02-21 23:47:00 +00001416
Benny Prijonoa91a0032006-02-26 21:23:45 +00001417pj_status_t pjsua_call_init(void)
1418{
1419 /* Initialize invite session callback. */
1420 pjsip_inv_callback inv_cb;
1421 pj_status_t status;
1422
1423 pj_memset(&inv_cb, 0, sizeof(inv_cb));
1424 inv_cb.on_state_changed = &pjsua_call_on_state_changed;
1425 inv_cb.on_new_session = &pjsua_call_on_forked;
1426 inv_cb.on_media_update = &pjsua_call_on_media_update;
1427 inv_cb.on_rx_offer = &pjsua_call_on_rx_offer;
1428 inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed;
1429
1430
1431 /* Initialize invite session module: */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001432 status = pjsip_inv_usage_init(pjsua.endpt, &inv_cb);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001433
1434 return status;
1435}