call-session.cpp 34.1 KB
Newer Older
1 2
/*
 * call-session.cpp
Ghislain MARY's avatar
Ghislain MARY committed
3
 * Copyright (C) 2010-2017 Belledonne Communications SARL
4
 *
Ghislain MARY's avatar
Ghislain MARY committed
5 6 7 8
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
9 10 11 12 13 14 15
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
Ghislain MARY's avatar
Ghislain MARY committed
16 17
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 19
 */

20
#include <bctoolbox/defs.h>
21

22
#include "c-wrapper/c-wrapper.h"
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

#include "address/address-p.h"
#include "conference/session/call-session-p.h"
#include "call/call-p.h"
#include "conference/params/call-session-params-p.h"

#include "conference/session/call-session.h"

#include "logger/logger.h"

#include "linphone/core.h"

#include "private.h"

using namespace std;
38 39 40 41 42

LINPHONE_BEGIN_NAMESPACE

// =============================================================================

43
CallSessionPrivate::CallSessionPrivate (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener)
44 45
	: conference(conference), listener(listener) {
	if (params)
46 47
		this->params = new CallSessionParams(*params);
	currentParams = new CallSessionParams();
48
	core = conference.getCore();
49 50 51 52
	ei = linphone_error_info_new();
}

CallSessionPrivate::~CallSessionPrivate () {
53 54 55 56 57 58
	if (currentParams)
		delete currentParams;
	if (params)
		delete params;
	if (remoteParams)
		delete remoteParams;
59 60 61 62 63
	if (ei)
		linphone_error_info_unref(ei);
	if (log)
		linphone_call_log_unref(log);
	if (op)
64
		op->release();
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
}

// -----------------------------------------------------------------------------

int CallSessionPrivate::computeDuration () const {
	if (log->connected_date_time == 0)
		return 0;
	return (int)(ms_time(nullptr) - log->connected_date_time);
}

/*
 * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote
 * end apparently does not support. This features are: privacy, video...
 */
void CallSessionPrivate::initializeParamsAccordingToIncomingCallParams () {
80
	currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy());
81 82 83
}

void CallSessionPrivate::setState(LinphoneCallState newState, const string &message) {
84
	L_Q();
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	if (state != newState){
		prevState = state;

		/* Make sanity checks with call state changes. Any bad transition can result in unpredictable results
		   or irrecoverable errors in the application. */
		if ((state == LinphoneCallEnd) || (state == LinphoneCallError)) {
			if (newState != LinphoneCallReleased) {
				lFatal() << "Abnormal call resurection from " << linphone_call_state_to_string(state) <<
					" to " << linphone_call_state_to_string(newState) << " , aborting";
				return;
			}
		} else if ((newState == LinphoneCallReleased) && (prevState != LinphoneCallError) && (prevState != LinphoneCallEnd)) {
			lFatal() << "Attempt to move CallSession [" << q << "] to Released state while it was not previously in Error or End state, aborting";
			return;
		}
		lInfo() << "CallSession [" << q << "] moving from state " << linphone_call_state_to_string(state) << " to " << linphone_call_state_to_string(newState);

		if (newState != LinphoneCallRefered) {
			/* LinphoneCallRefered is rather an event, not a state.
			   Indeed it does not change the state of the call (still paused or running). */
			state = newState;
		}

		switch (newState) {
			case LinphoneCallOutgoingInit:
			case LinphoneCallIncomingReceived:
Benjamin REIS's avatar
Benjamin REIS committed
111 112 113
				getPlatformHelpers(core)->acquireWifiLock();
				getPlatformHelpers(core)->acquireMcastLock();
				getPlatformHelpers(core)->acquireCpuLock();
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
				break;
			case LinphoneCallEnd:
			case LinphoneCallError:
				switch (linphone_error_info_get_reason(q->getErrorInfo())) {
					case LinphoneReasonDeclined:
						log->status = LinphoneCallDeclined;
						break;
					case LinphoneReasonNotAnswered:
						if (log->dir == LinphoneCallIncoming)
							log->status = LinphoneCallMissed;
						break;
					case LinphoneReasonNone:
						if (log->dir == LinphoneCallIncoming) {
							if (ei) {
								int code = linphone_error_info_get_protocol_code(ei);
								if ((code >= 200) && (code < 300))
									log->status = LinphoneCallAcceptedElsewhere;
							}
						}
						break;
					case LinphoneReasonDoNotDisturb:
						if (log->dir == LinphoneCallIncoming) {
							if (ei) {
								int code = linphone_error_info_get_protocol_code(ei);
								if ((code >= 600) && (code < 700))
									log->status = LinphoneCallDeclinedElsewhere;
							}
						}
						break;
					default:
						break;
				}
				setTerminated();
				break;
			case LinphoneCallConnected:
				log->status = LinphoneCallSuccess;
				log->connected_date_time = ms_time(nullptr);
				break;
			case LinphoneCallReleased:
Benjamin REIS's avatar
Benjamin REIS committed
153 154 155
				getPlatformHelpers(core)->acquireWifiLock();
				getPlatformHelpers(core)->acquireMcastLock();
				getPlatformHelpers(core)->acquireCpuLock();
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
				break;
			default:
				break;
		}

		if (newState != LinphoneCallStreamsRunning) {
#if 0 // TODO
			if (call->dtmfs_timer!=NULL){
				/*cancelling DTMF sequence, if any*/
				linphone_call_cancel_dtmfs(call);
			}
#endif
		}
		if (message.empty()) {
			lError() << "You must fill a reason when changing call state (from " <<
				linphone_call_state_to_string(prevState) << " to " << linphone_call_state_to_string(state) << ")";
		}
		if (listener)
174
			listener->onCallSessionStateChanged(q->getSharedFromThis(), state, message);
175 176 177 178 179 180 181 182 183 184 185
		if (newState == LinphoneCallReleased)
			setReleased(); /* Shall be performed after app notification */
	}
}

bool CallSessionPrivate::startPing () {
	if (core->sip_conf.ping_with_options) {
		/* Defer the start of the call after the OPTIONS ping for outgoing call or
		 * send an option request back to the caller so that we get a chance to discover our nat'd address
		 * before answering for incoming call */
		pingReplied = false;
186
		pingOp = new SalOp(core->sal);
187
		if (direction == LinphoneCallIncoming) {
188 189
			const char *from = pingOp->get_from();
			const char *to = pingOp->get_to();
190
			linphone_configure_op(core, pingOp, log->from, nullptr, false);
191 192
			pingOp->set_route(op->get_network_origin());
			pingOp->ping(from, to);
193 194 195
		} else if (direction == LinphoneCallOutgoing) {
			char *from = linphone_address_as_string(log->from);
			char *to = linphone_address_as_string(log->to);
196
			pingOp->ping(from, to);
197 198 199
			ms_free(from);
			ms_free(to);
		}
200
		pingOp->set_user_pointer(this);
201 202 203 204 205 206 207
		return true;
	}
	return false;
}

// -----------------------------------------------------------------------------

208
void CallSessionPrivate::abort (const string &errorMsg) {
209
	op->terminate();
210 211 212
	setState(LinphoneCallError, errorMsg);
}

213 214 215 216 217 218 219 220 221 222 223 224
void CallSessionPrivate::accepted () {
	/* Immediately notify the connected state, even if errors occur after */
	switch (state) {
		case LinphoneCallOutgoingProgress:
		case LinphoneCallOutgoingRinging:
		case LinphoneCallOutgoingEarlyMedia:
			/* Immediately notify the connected state */
			setState(LinphoneCallConnected, "Connected");
			break;
		default:
			break;
	}
225
	currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy());
226 227 228
}

void CallSessionPrivate::ackBeingSent (LinphoneHeaders *headers) {
229
	L_Q();
230
	if (listener)
231
		listener->onAckBeingSent(q->getSharedFromThis(), headers);
232 233 234
}

void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) {
235
	L_Q();
236
	if (listener)
237
		listener->onAckReceived(q->getSharedFromThis(), headers);
238 239 240
}

bool CallSessionPrivate::failure () {
241
	L_Q();
242
	const SalErrorInfo *ei = op->get_error_info();
243 244 245 246
	switch (ei->reason) {
		case SalReasonRedirect:
			if ((state == LinphoneCallOutgoingInit) || (state == LinphoneCallOutgoingProgress)
				|| (state == LinphoneCallOutgoingRinging) /* Push notification case */ || (state == LinphoneCallOutgoingEarlyMedia)) {
247
				const SalAddress *redirectionTo = op->get_remote_contact_address();
248 249 250 251 252 253 254
				if (redirectionTo) {
					char *url = sal_address_as_string(redirectionTo);
					lWarning() << "Redirecting CallSession [" << q << "] to " << url;
					if (log->to)
						linphone_address_unref(log->to);
					log->to = linphone_address_new(url);
					ms_free(url);
255
					restartInvite();
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
					return true;
				}
			}
			break;
		default:
			break;
	}

	/* Some call errors are not fatal */
	switch (state) {
		case LinphoneCallUpdating:
		case LinphoneCallPausing:
		case LinphoneCallResuming:
			if (ei->reason != SalReasonNoMatch) {
				lInfo() << "Call error on state [" << linphone_call_state_to_string(state) << "], restoring previous state [" << linphone_call_state_to_string(prevState) << "]";
				setState(prevState, ei->full_string);
				return true;
			}
		default:
			break;
	}

	if ((state != LinphoneCallEnd) && (state != LinphoneCallError)) {
		if (ei->reason == SalReasonDeclined)
			setState(LinphoneCallEnd, "Call declined");
		else {
			if (linphone_call_state_is_early(state))
283
				setState(LinphoneCallError, ei->full_string ? ei->full_string : "");
284
			else
285
				setState(LinphoneCallEnd, ei->full_string ? ei->full_string : "");
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
		}
#if 0 // TODO: handle in Call class
		if (ei->reason != SalReasonNone)
			linphone_core_play_call_error_tone(core, linphone_reason_from_sal(ei->reason));
#endif
	}
#if 0
	LinphoneCall *referer=call->referer;
	if (referer){
		/*notify referer of the failure*/
		linphone_core_notify_refer_state(lc,referer,call);
		/*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/
		linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer");
	}
#endif
	return false;
}

void CallSessionPrivate::pingReply () {
305
	L_Q();
306 307 308
	if (state == LinphoneCallOutgoingInit) {
		pingReplied = true;
		if (isReadyForInvite())
309
			q->startInvite(nullptr, "");
310 311 312 313
	}
}

void CallSessionPrivate::remoteRinging () {
314
	L_Q();
315
	/* Set privacy */
316
	q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)op->get_privacy());
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
#if 0
	if (lc->ringstream == NULL) start_remote_ring(lc, call);
#endif
	lInfo() << "Remote ringing...";
	setState(LinphoneCallOutgoingRinging, "Remote ringing");
}

void CallSessionPrivate::terminated () {
	switch (state) {
		case LinphoneCallEnd:
		case LinphoneCallError:
			lWarning() << "terminated: already terminated, ignoring";
			return;
		case LinphoneCallIncomingReceived:
		case LinphoneCallIncomingEarlyMedia:
332
			if (!op->get_reason_error_info()->protocol || strcmp(op->get_reason_error_info()->protocol, "") == 0) {
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
				linphone_error_info_set(ei, nullptr, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", nullptr);
				nonOpError = true;
			}
			break;
		default:
			break;
	}
#if 0
	if (call->refer_pending)
		linphone_core_start_refered_call(lc,call,NULL);
	//we stop the call only if we have this current call or if we are in call
	if ((bctbx_list_size(lc->calls)  == 1) || linphone_core_in_call(lc)) {
		linphone_core_stop_ringing(lc);
	}
#endif
	setState(LinphoneCallEnd, "Call ended");
}

void CallSessionPrivate::updated (bool isUpdate) {
352
	deferUpdate = !!lp_config_get_int(linphone_core_get_config(core), "sip", "defer_update_default", FALSE);
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
	SalErrorInfo sei;
	memset(&sei, 0, sizeof(sei));
	switch (state) {
		case LinphoneCallPausedByRemote:
			updatedByRemote();
			break;
		/* SIP UPDATE CASE */
		case LinphoneCallOutgoingRinging:
		case LinphoneCallOutgoingEarlyMedia:
		case LinphoneCallIncomingEarlyMedia:
			if (isUpdate) {
				setState(LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote");
				acceptUpdate(nullptr, prevState, linphone_call_state_to_string(prevState));
			}
			break;
		case LinphoneCallStreamsRunning:
		case LinphoneCallConnected:
		case LinphoneCallUpdatedByRemote: /* Can happen on UAC connectivity loss */
			updatedByRemote();
			break;
		case LinphoneCallPaused:
			/* We'll remain in pause state but accept the offer anyway according to default parameters */
			acceptUpdate(nullptr, state, linphone_call_state_to_string(state));
			break;
		case LinphoneCallUpdating:
		case LinphoneCallPausing:
		case LinphoneCallResuming:
			sal_error_info_set(&sei, SalReasonInternalError, "SIP", 0, nullptr, nullptr);
381
			op->decline_with_error_info(&sei, nullptr);
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
			BCTBX_NO_BREAK; /* no break */
		case LinphoneCallIdle:
		case LinphoneCallOutgoingInit:
		case LinphoneCallEnd:
		case LinphoneCallIncomingReceived:
		case LinphoneCallOutgoingProgress:
		case LinphoneCallRefered:
		case LinphoneCallError:
		case LinphoneCallReleased:
		case LinphoneCallEarlyUpdatedByRemote:
		case LinphoneCallEarlyUpdating:
			lWarning() << "Receiving reINVITE or UPDATE while in state [" << linphone_call_state_to_string(state) << "], should not happen";
		break;
	}
}

void CallSessionPrivate::updatedByRemote () {
399
	L_Q();
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
	setState(LinphoneCallUpdatedByRemote,"Call updated by remote");
	if (deferUpdate) {
		if (state == LinphoneCallUpdatedByRemote)
			lInfo() << "CallSession [" << q << "]: UpdatedByRemoted was signaled but defered. LinphoneCore expects the application to call linphone_core_accept_call_update() later.";
	} else {
		if (state == LinphoneCallUpdatedByRemote)
			q->acceptUpdate(nullptr);
		else {
			/* Otherwise it means that the app responded by linphone_core_accept_call_update
			 * within the callback, so job is already done. */
		}
	}
}

void CallSessionPrivate::updating (bool isUpdate) {
	updated(isUpdate);
}

// -----------------------------------------------------------------------------

420
void CallSessionPrivate::accept (const CallSessionParams *params) {
421
	L_Q();
422 423 424
	/* Try to be best-effort in giving real local or routable contact address */
	setContactOp();
	if (params) {
425
		this->params = new CallSessionParams(*params);
426
		op->set_sent_custom_header(this->params->getPrivate()->getCustomHeaders());
427 428
	}

429
	op->accept();
430
	if (listener)
431
		listener->onSetCurrentSession(q->getSharedFromThis());
432 433 434
	setState(LinphoneCallConnected, "Connected");
}

435
LinphoneStatus CallSessionPrivate::acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const string &stateInfo) {
436 437 438 439
	return startAcceptUpdate(nextState, stateInfo);
}

LinphoneStatus CallSessionPrivate::checkForAcceptation () const {
440
	L_Q();
441 442 443 444 445 446 447 448
	switch (state) {
		case LinphoneCallIncomingReceived:
		case LinphoneCallIncomingEarlyMedia:
			break;
		default:
			lError() << "checkForAcceptation() CallSession [" << q << "] is in state [" << linphone_call_state_to_string(state) << "], operation not permitted";
			return -1;
	}
449
	if (listener)
450
		listener->onCheckForAcceptation(q->getSharedFromThis());
451 452

	/* Check if this call is supposed to replace an already running one */
453
	SalOp *replaced = op->get_replaces();
454
	if (replaced) {
455
		CallSession *session = reinterpret_cast<CallSession *>(replaced->get_user_pointer());
456 457 458 459 460 461 462 463 464
		if (session) {
			lInfo() << "CallSession " << q << " replaces CallSession " << session << ". This last one is going to be terminated automatically";
			session->terminate();
		}
	}
	return 0;
}

void CallSessionPrivate::handleIncomingReceivedStateInIncomingNotification () {
465
	L_Q();
466 467
	/* Try to be best-effort in giving real local or routable contact address for 100Rel case */
	setContactOp();
468 469
	op->notify_ringing(false);
	if (op->get_replaces() && lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1))
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
		q->accept();
}

bool CallSessionPrivate::isReadyForInvite () const {
	bool pingReady = false;
	if (pingOp) {
		if (pingReplied)
			pingReady = true;
	} else
		pingReady = true;
	return pingReady;
}

bool CallSessionPrivate::isUpdateAllowed (LinphoneCallState &nextState) const {
	switch (state) {
		case LinphoneCallIncomingReceived:
		case LinphoneCallIncomingEarlyMedia:
		case LinphoneCallOutgoingRinging:
		case LinphoneCallOutgoingEarlyMedia:
			nextState = LinphoneCallEarlyUpdating;
			break;
491
		case LinphoneCallConnected:
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
		case LinphoneCallStreamsRunning:
		case LinphoneCallPausedByRemote:
		case LinphoneCallUpdatedByRemote:
			nextState = LinphoneCallUpdating;
			break;
		case LinphoneCallPaused:
			nextState = LinphoneCallPausing;
			break;
		case LinphoneCallOutgoingProgress:
		case LinphoneCallPausing:
		case LinphoneCallResuming:
		case LinphoneCallUpdating:
			nextState = state;
			break;
		default:
			lError() << "Update is not allowed in [" << linphone_call_state_to_string(state) << "] state";
			return false;
	}
	return true;
}

513 514 515 516 517 518
int CallSessionPrivate::restartInvite () {
	L_Q();
	createOp();
	return q->startInvite(nullptr, subject);
}

519 520 521 522
/*
 * Called internally when reaching the Released state, to perform cleanups to break circular references.
**/
void CallSessionPrivate::setReleased () {
523
	L_Q();
524 525 526 527 528
	if (op) {
		/* Transfer the last error so that it can be obtained even in Released state */
		if (!nonOpError)
			linphone_error_info_from_sal_op(ei, op);
		/* So that we cannot have anymore upcalls for SAL concerning this call */
529
		op->release();
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
		op = nullptr;
	}
#if 0
	/* It is necessary to reset pointers to other call to prevent circular references that would result in memory never freed */
	if (call->referer){
		linphone_call_unref(call->referer);
		call->referer=NULL;
	}
	if (call->transfer_target){
		linphone_call_unref(call->transfer_target);
		call->transfer_target=NULL;
	}
	if (call->chat_room){
		linphone_chat_room_unref(call->chat_room);
		call->chat_room = NULL;
	}
#endif
	if (listener)
548
		listener->onCallSessionSetReleased(q->getSharedFromThis());
549 550 551 552 553 554 555 556
}

/* This method is called internally to get rid of a call that was notified to the application,
 * because it reached the end or error state. It performs the following tasks:
 * - remove the call from the internal list of calls
 * - update the call logs accordingly
 */
void CallSessionPrivate::setTerminated() {
557
	L_Q();
558 559
	completeLog();
	if (listener)
560
		listener->onCallSessionSetTerminated(q->getSharedFromThis());
561 562
}

563 564
LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) {
	op->accept();
565 566 567 568
	setState(nextState, stateInfo);
	return 0;
}

569
LinphoneStatus CallSessionPrivate::startUpdate (const string &subject) {
570
	L_Q();
571 572 573 574 575 576 577 578 579 580 581
	string newSubject(subject);
	if (newSubject.empty()) {
		if (q->getParams()->getPrivate()->getInConference())
			newSubject = "Conference";
		else if (q->getParams()->getPrivate()->getInternalCallUpdate())
			newSubject = "ICE processing concluded";
		else if (q->getParams()->getPrivate()->getNoUserConsent())
			newSubject = "Refreshing";
		else
			newSubject = "Media change";
	}
582 583
	if (destProxy && destProxy->op) {
		/* Give a chance to update the contact address if connectivity has changed */
584
		op->set_contact_address(destProxy->op->get_contact_address());
585
	} else
586
		op->set_contact_address(nullptr);
587
	return op->update(newSubject.c_str(), q->getParams()->getPrivate()->getNoUserConsent());
588 589 590 591 592 593 594 595 596 597
}

void CallSessionPrivate::terminate () {
	if ((state == LinphoneCallIncomingReceived) && (linphone_error_info_get_reason(ei) != LinphoneReasonNotAnswered)) {
		linphone_error_info_set_reason(ei, LinphoneReasonDeclined);
		nonOpError = true;
	}
	setState(LinphoneCallEnd, "Call terminated");
}

598
void CallSessionPrivate::updateCurrentParams () const {}
599 600 601 602 603 604 605

// -----------------------------------------------------------------------------

void CallSessionPrivate::setContactOp () {
	SalAddress *salAddress = nullptr;
	LinphoneAddress *contact = getFixedContact();
	if (contact) {
606
		salAddress = const_cast<SalAddress *>(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress());
607
		op->set_contact_address(salAddress);
Ghislain MARY's avatar
Ghislain MARY committed
608
		linphone_address_unref(contact);
609 610 611 612 613 614 615 616
	}
}

// -----------------------------------------------------------------------------

void CallSessionPrivate::completeLog () {
	log->duration = computeDuration(); /* Store duration since connected */
	log->error_info = linphone_error_info_ref(ei);
617
	if (log->status == LinphoneCallMissed)
618 619 620 621
		core->missed_calls++;
	linphone_core_report_call_log(core, log);
}

622 623 624 625
void CallSessionPrivate::createOp () {
	createOpTo(log->to);
}

626
void CallSessionPrivate::createOpTo (const LinphoneAddress *to) {
627
	L_Q();
628
	if (op)
629 630 631
		op->release();
	op = new SalCallOp(core->sal);
	op->set_user_pointer(q);
632 633 634 635 636 637
#if 0
	if (linphone_call_params_get_referer(call->params))
		sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op);
#endif
	linphone_configure_op(core, op, to, q->getParams()->getPrivate()->getCustomHeaders(), false);
	if (q->getParams()->getPrivacy() != LinphonePrivacyDefault)
638
		op->set_privacy((SalPrivacyMask)q->getParams()->getPrivacy());
639 640 641 642 643 644 645
	/* else privacy might be set by proxy */
}

// -----------------------------------------------------------------------------

LinphoneAddress * CallSessionPrivate::getFixedContact () const {
	LinphoneAddress *result = nullptr;
646
	if (op && op->get_contact_address()) {
647 648
		/* If already choosed, don't change it */
		return nullptr;
649
	} else if (pingOp && pingOp->get_contact_address()) {
650 651
		/* If the ping OPTIONS request succeeded use the contact guessed from the received, rport */
		lInfo() << "Contact has been fixed using OPTIONS";
652
		char *addr = sal_address_as_string(pingOp->get_contact_address());
653 654
		result = linphone_address_new(addr);
		ms_free(addr);
655
	} else if (destProxy && destProxy->op && _linphone_proxy_config_get_contact_without_params(destProxy)) {
656 657
		/* If using a proxy, use the contact address as guessed with the REGISTERs */
		lInfo() << "Contact has been fixed using proxy";
658
		result = linphone_address_clone(_linphone_proxy_config_get_contact_without_params(destProxy));
659 660 661 662 663 664 665 666 667 668 669 670 671 672
	} else {
		result = linphone_core_get_primary_contact_parsed(core);
		if (result) {
			/* Otherwise use supplied localip */
			linphone_address_set_domain(result, nullptr /* localip */);
			linphone_address_set_port(result, -1 /* linphone_core_get_sip_port(core) */);
			lInfo() << "Contact has not been fixed, stack will do";
		}
	}
	return result;
}

// =============================================================================

673
CallSession::CallSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener)
674 675 676 677
	: Object(*new CallSessionPrivate(conference, params, listener)) {
	lInfo() << "New CallSession [" << this << "] initialized (LinphoneCore version: " << linphone_core_get_version() << ")";
}

678 679
CallSession::CallSession (CallSessionPrivate &p) : Object(p) {}

680 681
// -----------------------------------------------------------------------------

682
LinphoneStatus CallSession::accept (const CallSessionParams *csp) {
683
	L_D();
684 685 686 687 688 689
	LinphoneStatus result = d->checkForAcceptation();
	if (result < 0) return result;
	d->accept(csp);
	return 0;
}

690
LinphoneStatus CallSession::acceptUpdate (const CallSessionParams *csp) {
691
	L_D();
692 693 694 695 696 697 698
	if (d->state != LinphoneCallUpdatedByRemote) {
		lError() << "CallSession::acceptUpdate(): invalid state " << linphone_call_state_to_string(d->state) << " to call this method";
		return -1;
	}
	return d->acceptUpdate(csp, d->prevState, linphone_call_state_to_string(d->prevState));
}

699
void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) {
700
	L_D();
701 702 703 704 705 706 707 708 709 710 711 712 713
	d->direction = direction;
	d->destProxy = cfg;
	LinphoneAddress *fromAddr = linphone_address_new(from.asString().c_str());
	LinphoneAddress *toAddr = linphone_address_new(to.asString().c_str());
	if (!d->destProxy) {
		/* Try to define the destination proxy if it has not already been done to have a correct contact field in the SIP messages */
		d->destProxy = linphone_core_lookup_known_proxy(d->core, toAddr);
	}
	d->log = linphone_call_log_new(direction, fromAddr, toAddr);

	if (op) {
		/* We already have an op for incoming calls */
		d->op = op;
714 715
		d->op->set_user_pointer(this);
		op->enable_cnx_ip_to_0000_if_sendonly(!!lp_config_get_default_int(linphone_core_get_config(d->core),
716
			"sip", "cnx_ip_to_0000_if_sendonly_enabled", 0));
717
		d->log->call_id = ms_strdup(op->get_call_id()); /* Must be known at that time */
718 719 720 721 722
	}

	if (direction == LinphoneCallOutgoing) {
		d->startPing();
	} else if (direction == LinphoneCallIncoming) {
723
		d->params = new CallSessionParams();
724 725 726 727 728 729 730 731 732 733 734 735 736
		d->params->initDefault(d->core);
	}
}

LinphoneStatus CallSession::decline (LinphoneReason reason) {
	LinphoneErrorInfo *ei = linphone_error_info_new();
	linphone_error_info_set(ei, "SIP", reason, linphone_reason_to_error_code(reason), nullptr, nullptr);
	LinphoneStatus status = decline(ei);
	linphone_error_info_unref(ei);
	return status;
}

LinphoneStatus CallSession::decline (const LinphoneErrorInfo *ei) {
737
	L_D();
738 739 740 741 742 743 744 745 746 747 748
	SalErrorInfo sei;
	SalErrorInfo sub_sei;
	memset(&sei, 0, sizeof(sei));
	memset(&sub_sei, 0, sizeof(sub_sei));
	sei.sub_sei = &sub_sei;
	if ((d->state != LinphoneCallIncomingReceived) && (d->state != LinphoneCallIncomingEarlyMedia)) {
		lError() << "Cannot decline a CallSession that is in state " << linphone_call_state_to_string(d->state);
		return -1;
	}
	if (ei) {
		linphone_error_info_to_sal(ei, &sei);
749
		d->op->decline_with_error_info(&sei , nullptr);
750
	} else
751
		d->op->decline(SalReasonDeclined, nullptr);
752 753 754 755 756 757 758 759 760
	sal_error_info_reset(&sei);
	sal_error_info_reset(&sub_sei);
	d->terminate();
	return 0;
}

void CallSession::initiateIncoming () {}

bool CallSession::initiateOutgoing () {
761
	L_D();
762 763 764 765 766 767 768 769 770 771 772 773
	bool defer = false;
	d->setState(LinphoneCallOutgoingInit, "Starting outgoing call");
	d->log->start_date_time = ms_time(nullptr);
	if (!d->destProxy)
		defer = d->startPing();
 	if (d->direction == LinphoneCallOutgoing) {
		d->createOpTo(d->log->to);
	}
	return defer;
}

void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) {
774
	L_D();
775 776 777
	int elapsed = (int)(currentRealTime - d->log->start_date_time);
	if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) {
		/* Start the call even if the OPTIONS reply did not arrive */
778
		startInvite(nullptr, "");
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
	}
	if ((d->state == LinphoneCallIncomingReceived) || (d->state == LinphoneCallIncomingEarlyMedia)) {
		if (oneSecondElapsed)
			lInfo() << "Incoming call ringing for " << elapsed << " seconds";
		if (elapsed > d->core->sip_conf.inc_timeout) {
			lInfo() << "Incoming call timeout (" << d->core->sip_conf.inc_timeout << ")";
#if 0
			LinphoneReason declineReason = (core->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined;
#endif
			d->log->status = LinphoneCallMissed;
#if 0
			call->non_op_error = TRUE;
			linphone_error_info_set(call->ei, NULL, decline_reason, linphone_reason_to_error_code(decline_reason), "Not answered", NULL);
			linphone_call_decline(call, decline_reason);
#endif
		}
	}
	if ((d->core->sip_conf.in_call_timeout > 0) && (d->log->connected_date_time != 0)
		&& ((currentRealTime - d->log->connected_date_time) > d->core->sip_conf.in_call_timeout)) {
		lInfo() << "In call timeout (" << d->core->sip_conf.in_call_timeout << ")";
		terminate();
	}
}

803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
LinphoneStatus CallSession::redirect (const string &redirectUri) {
	L_D();
	LinphoneAddress *realParsedAddr = linphone_core_interpret_url(d->core, redirectUri.c_str());
	if (!realParsedAddr) {
		/* Bad url */
		lError() << "Bad redirect URI: " << redirectUri;
		return -1;
	}
	char *realParsedUri = linphone_address_as_string(realParsedAddr);
	Address redirectAddr(realParsedUri);
	bctbx_free(realParsedUri);
	linphone_address_unref(realParsedAddr);
	return redirect(redirectAddr);
}

LinphoneStatus CallSession::redirect (const Address &redirectAddr) {
	L_D();
	if (d->state != LinphoneCallIncomingReceived) {
		lError() << "Bad state for CallSession redirection";
		return -1;
	}
	SalErrorInfo sei;
	memset(&sei, 0, sizeof(sei));
	sal_error_info_set(&sei, SalReasonRedirect, "SIP", 0, nullptr, nullptr);
	d->op->decline_with_error_info(&sei, redirectAddr.getPrivate()->getInternalAddress());
	linphone_error_info_set(d->ei, nullptr, LinphoneReasonMovedPermanently, 302, "Call redirected", nullptr);
	d->nonOpError = true;
	d->terminate();
	sal_error_info_reset(&sei);
	return 0;
}

835
void CallSession::startIncomingNotification () {
836
	L_D();
837
	if (d->listener)
838
		d->listener->onCallSessionAccepted(getSharedFromThis());
839
	/* Prevent the CallSession from being destroyed while we are notifying, if the user declines within the state callback */
840
	shared_ptr<CallSession> ref = getSharedFromThis();
841 842 843 844
#if 0
	call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL);
#endif
	if (d->deferIncomingNotification) {
845
		lInfo() << "Defer incoming notification";
846 847 848 849
		return;
	}

	if (d->listener)
850
		d->listener->onIncomingCallSessionStarted(getSharedFromThis());
851

852
	d->setState(LinphoneCallIncomingReceived, "Incoming CallSession");
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867

	/* From now on, the application is aware of the call and supposed to take background task or already submitted notification to the user.
	 * We can then drop our background task. */
#if 0
	if (call->bg_task_id!=0) {
		sal_end_background_task(call->bg_task_id);
		call->bg_task_id=0;
	}
#endif

	if (d->state == LinphoneCallIncomingReceived) {
		d->handleIncomingReceivedStateInIncomingNotification();
	}
}

868
int CallSession::startInvite (const Address *destination, const string &subject, const Content *content) {
869
	L_D();
870
	d->subject = subject;
871 872 873 874 875 876 877 878 879 880 881 882 883
	/* Try to be best-effort in giving real local or routable contact address */
	d->setContactOp();
	string destinationStr;
	char *realUrl = nullptr;
	if (destination)
		destinationStr = destination->asString();
	else {
		realUrl = linphone_address_as_string(d->log->to);
		destinationStr = realUrl;
		ms_free(realUrl);
	}
	char *from = linphone_address_as_string(d->log->from);
	/* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */
884
	shared_ptr<CallSession> ref = getSharedFromThis();
885 886
	if (content)
		d->op->set_local_body(*content);
887
	int result = d->op->call(from, destinationStr.c_str(), subject.empty() ? nullptr : subject.c_str());
888 889 890 891 892 893 894 895
	ms_free(from);
	if (result < 0) {
		if ((d->state != LinphoneCallError) && (d->state != LinphoneCallReleased)) {
			/* sal_call() may invoke call_failure() and call_released() SAL callbacks synchronously,
			   in which case there is no need to perform a state change here. */
			d->setState(LinphoneCallError, "Call failed");
		}
	} else {
896
		d->log->call_id = ms_strdup(d->op->get_call_id()); /* Must be known at that time */
897 898 899 900 901 902
		d->setState(LinphoneCallOutgoingProgress, "Outgoing call in progress");
	}
	return result;
}

LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) {
903
	L_D();
904 905 906 907 908 909 910 911 912 913 914 915 916 917
	lInfo() << "Terminate CallSession [" << this << "] which is currently in state [" << linphone_call_state_to_string(d->state) << "]";
	SalErrorInfo sei;
	memset(&sei, 0, sizeof(sei));
	switch (d->state) {
		case LinphoneCallReleased:
		case LinphoneCallEnd:
		case LinphoneCallError:
			lWarning() << "No need to terminate CallSession [" << this << "] in state [" << linphone_call_state_to_string(d->state) << "]";
			return -1;
		case LinphoneCallIncomingReceived:
		case LinphoneCallIncomingEarlyMedia:
			return decline(ei);
		case LinphoneCallOutgoingInit:
			/* In state OutgoingInit, op has to be destroyed */
918
			d->op->release();
919 920 921 922 923
			d->op = nullptr;
			break;
		default:
			if (ei) {
				linphone_error_info_to_sal(ei, &sei);
924
				d->op->terminate_with_error(&sei);
925 926
				sal_error_info_reset(&sei);
			} else
927
				d->op->terminate();
928 929 930 931 932 933 934
			break;
	}

	d->terminate();
	return 0;
}

935
LinphoneStatus CallSession::update (const CallSessionParams *csp, const string &subject, const Content *content) {
936
	L_D();
937 938 939 940
	LinphoneCallState nextState;
	LinphoneCallState initialState = d->state;
	if (!d->isUpdateAllowed(nextState))
		return -1;
941
	if (d->currentParams == csp)
942
		lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!";
943 944 945
	if (csp)
		d->params = new CallSessionParams(*csp);
	d->op->set_local_body(content ? *content : Content());
946
	LinphoneStatus result = d->startUpdate(subject);
947 948 949 950 951 952 953 954 955 956
	if (result && (d->state != initialState)) {
		/* Restore initial state */
		d->setState(initialState, "Restore initial state");
	}
	return result;
}

// -----------------------------------------------------------------------------

LinphoneCallDir CallSession::getDirection () const {
957
	L_D();
958 959 960 961
	return d->direction;
}

int CallSession::getDuration () const {
962
	L_D();
963 964 965 966 967 968 969 970 971 972 973
	switch (d->state) {
		case LinphoneCallEnd:
		case LinphoneCallError:
		case LinphoneCallReleased:
			return d->log->duration;
		default:
			return d->computeDuration();
	}
}

const LinphoneErrorInfo * CallSession::getErrorInfo () const {
974
	L_D();
975 976 977 978 979 980
	if (!d->nonOpError)
		linphone_error_info_from_sal_op(d->ei, d->op);
	return d->ei;
}

LinphoneCallLog * CallSession::getLog () const {
981
	L_D();
982 983 984 985 986 987 988 989
	return d->log;
}

LinphoneReason CallSession::getReason () const {
	return linphone_error_info_get_reason(getErrorInfo());
}

const Address& CallSession::getRemoteAddress () const {
990
	L_D();
991
	return *L_GET_CPP_PTR_FROM_C_OBJECT((d->direction == LinphoneCallIncoming)
992
		? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log));
993 994 995 996 997 998 999
}

string CallSession::getRemoteAddressAsString () const {
	return getRemoteAddress().asString();
}

string CallSession::getRemoteContact () const {
1000
	L_D();
1001 1002
	if (d->op) {
		/* sal_op_get_remote_contact preserves header params */
1003
		return d->op->get_remote_contact();
1004 1005 1006 1007
	}
	return string();
}

1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
const Address *CallSession::getRemoteContactAddress () const {
	L_D();
	if (!d->op) {
		return nullptr;
	}
	char *addrStr = sal_address_as_string(d->op->get_remote_contact_address());
	d->remoteContactAddress = Address(addrStr);
	bctbx_free(addrStr);
	return &d->remoteContactAddress;
}

1019
const CallSessionParams * CallSession::getRemoteParams () {
1020
	L_D();
1021
	if (d->op){
1022
		const SalCustomHeader *ch = d->op->get_recv_custom_header();
1023 1024 1025
		if (ch) {
			/* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */
			if (!d->remoteParams)
1026
				d->remoteParams = new CallSessionParams();
1027 1028 1029 1030 1031 1032 1033 1034
			d->remoteParams->getPrivate()->setCustomHeaders(ch);
		}
		return d->remoteParams;
	}
	return nullptr;
}

LinphoneCallState CallSession::getState () const {
1035
	L_D();
1036 1037 1038 1039 1040 1041
	return d->state;
}

// -----------------------------------------------------------------------------

string CallSession::getRemoteUserAgent () const {
1042
	L_D();
1043
	if (d->op)
1044
		return d->op->get_remote_ua();
1045 1046 1047
	return string();
}

1048
CallSessionParams * CallSession::getCurrentParams () const {
1049
	L_D();
1050 1051 1052 1053 1054 1055
	d->updateCurrentParams();
	return d->currentParams;
}

// -----------------------------------------------------------------------------

1056
const CallSessionParams * CallSession::getParams () const {
1057
	L_D();
1058 1059 1060
	return d->params;
}

1061
LINPHONE_END_NAMESPACE