call.cpp 41.2 KB
Newer Older
1
/*
Simon Morlat's avatar
Simon Morlat committed
2
 * Copyright (c) 2010-2019 Belledonne Communications SARL.
3
 *
Simon Morlat's avatar
Simon Morlat committed
4 5 6 7 8 9
 * This file is part of Liblinphone.
 *
 * 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 3 of the License, or
 * (at your option) any later version.
10 11 12 13 14 15 16
 *
 * 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
Simon Morlat's avatar
Simon Morlat committed
17
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 19
 */

Ghislain MARY's avatar
Ghislain MARY committed
20
#include "c-wrapper/c-wrapper.h"
21
#include "call.h"
22
#include "chat/chat-room/abstract-chat-room-p.h"
23
#include "conference/params/media-session-params-p.h"
24
#include "conference/session/call-session-p.h"
25
#include "conference/session/media-session-p.h"
Andrea Gianarda's avatar
Andrea Gianarda committed
26
#include "conference/participant.h"
27
#include "core/core-p.h"
28
#include "logger/logger.h"
Andrea Gianarda's avatar
Andrea Gianarda committed
29
#include "conference/handlers/remote-conference-event-handler.h"
30

Ghislain MARY's avatar
Ghislain MARY committed
31
#include "conference_private.h"
Andrea Gianarda's avatar
Andrea Gianarda committed
32 33

#include <bctoolbox/defs.h>
Ghislain MARY's avatar
Ghislain MARY committed
34

35
// =============================================================================
36 37 38

using namespace std;

39
LINPHONE_BEGIN_NAMESPACE
40

41 42
// =============================================================================
shared_ptr<CallSession> Call::getActiveSession () const {
Andrea Gianarda's avatar
Andrea Gianarda committed
43
	return mParticipant->getSession();
44 45
}

46
shared_ptr<AbstractChatRoom> Call::getChatRoom () {
47
	if ((getState() != CallSession::State::End) && (getState() != CallSession::State::Released)) {
48 49
		mChatRoom = getCore()->getOrCreateBasicChatRoom(*getRemoteAddress());
		if (mChatRoom) {
50
			const char *callId = linphone_call_log_get_call_id(getLog());
51 52
			lInfo() << "Setting call id [" << callId << "] to ChatRoom [" << mChatRoom << "]";
			mChatRoom->getPrivate()->setCallId(callId);
53
		}
Ghislain MARY's avatar
Ghislain MARY committed
54
	}
55
	return mChatRoom;
Ghislain MARY's avatar
Ghislain MARY committed
56 57
}

58
LinphoneProxyConfig *Call::getDestProxy () const {
59 60 61
	return getActiveSession()->getPrivate()->getDestProxy();
}

Simon Morlat's avatar
Simon Morlat committed
62
/* This a test-only method.*/
63
IceSession *Call::getIceSession () const {
Ronan's avatar
Ronan committed
64
	return static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->getIceSession();
Simon Morlat's avatar
Simon Morlat committed
65
	return nullptr;
66 67
}

68
unsigned int Call::getAudioStartCount () const {
69 70 71
	return static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->getAudioStartCount();
}

72
unsigned int Call::getVideoStartCount () const {
73 74 75
	return static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->getVideoStartCount();
}

76
unsigned int Call::getTextStartCount () const {
77
	return static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->getTextStartCount();
78 79
}

80
std::shared_ptr<MediaSession> Call::getMediaSession()const{
Simon Morlat's avatar
Simon Morlat committed
81 82 83
	return static_pointer_cast<MediaSession>(getActiveSession());
}

84
MediaStream *Call::getMediaStream (LinphoneStreamType type) const {
Simon Morlat's avatar
Simon Morlat committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	auto ms = static_pointer_cast<MediaSession>(getActiveSession())->getPrivate();
	StreamsGroup & sg = ms->getStreamsGroup();
	MS2Stream *s = nullptr;
	switch(type){
		case LinphoneStreamTypeAudio:
			s = sg.lookupMainStreamInterface<MS2Stream>(SalAudio);
		break;
		case LinphoneStreamTypeVideo:
			s = sg.lookupMainStreamInterface<MS2Stream>(SalVideo);
		break;
		case LinphoneStreamTypeText:
			s = sg.lookupMainStreamInterface<MS2Stream>(SalText);
		break;
		default:
		break;
	}
	if (!s){
102
		//lError() << "CallPrivate::getMediaStream() : no stream with type " << type;
Simon Morlat's avatar
Simon Morlat committed
103 104 105
		return nullptr;
	}
	return s->getMediaStream();
106 107
}

108
SalCallOp * Call::getOp () const {
109 110 111
	return getActiveSession()->getPrivate()->getOp();
}

112
bool Call::getSpeakerMuted () const {
113 114 115
	return static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->getSpeakerMuted();
}

116
void Call::setSpeakerMuted (bool muted) {
117 118 119
	static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->setSpeakerMuted(muted);
}

120
bool Call::getMicrophoneMuted () const {
121 122 123
	return static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->getMicrophoneMuted();
}

124
void Call::setMicrophoneMuted (bool muted) {
125
	static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->setMicrophoneMuted(muted);
126 127
}

128
LinphoneCallStats *Call::getPrivateStats (LinphoneStreamType type) const {
129 130 131
	return static_pointer_cast<const MediaSession>(getActiveSession())->getPrivate()->getStats(type);
}

132
// =============================================================================
133

134
void Call::initiateIncoming () {
135 136 137
	getActiveSession()->initiateIncoming();
}

138
bool Call::initiateOutgoing () {
Ghislain MARY's avatar
Ghislain MARY committed
139 140
	shared_ptr<CallSession> session = getActiveSession();
	bool defer = session->initiateOutgoing();
Sylvain Berfini's avatar
Sylvain Berfini committed
141
	
142
	AudioDevice *outputAudioDevice = getCore()->getDefaultOutputAudioDevice();
Sylvain Berfini's avatar
Sylvain Berfini committed
143
	if (outputAudioDevice) {
144
		setOutputAudioDevicePrivate(outputAudioDevice);
Sylvain Berfini's avatar
Sylvain Berfini committed
145
	} else {
146
		lWarning() << "Failed to find audio device matching default output sound card [" << getCore()->getCCore()->sound_conf.play_sndcard << "]";
Sylvain Berfini's avatar
Sylvain Berfini committed
147 148
	}

149
	AudioDevice *inputAudioDevice = getCore()->getDefaultInputAudioDevice();
Sylvain Berfini's avatar
Sylvain Berfini committed
150
	if (inputAudioDevice) {
151
		setInputAudioDevicePrivate(inputAudioDevice);
Sylvain Berfini's avatar
Sylvain Berfini committed
152
	} else {
153
		lWarning() << "Failed to find audio device matching default input sound card [" << getCore()->getCCore()->sound_conf.capt_sndcard << "]";
Sylvain Berfini's avatar
Sylvain Berfini committed
154 155
	}

Ghislain MARY's avatar
Ghislain MARY committed
156 157
	session->getPrivate()->createOp();
	return defer;
158 159
}

160
void Call::iterate (time_t currentRealTime, bool oneSecondElapsed) {
161 162 163
	getActiveSession()->iterate(currentRealTime, oneSecondElapsed);
}

164
void Call::startIncomingNotification () {
165 166 167
	getActiveSession()->startIncomingNotification();
}

168 169 170 171 172 173 174 175 176
void Call::startPushIncomingNotification () {
	getActiveSession()->startPushIncomingNotification();
}

void Call::startBasicIncomingNotification () {
	getActiveSession()->startBasicIncomingNotification();
}

void Call::pauseForTransfer () {
177 178 179
	static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->pauseForTransfer();
}

180
int Call::startInvite (const Address *destination) {
181
	return getActiveSession()->startInvite(destination, "");
182 183
}

184 185
shared_ptr<Call> Call::startReferredCall (const MediaSessionParams *params) {
	if (getState() != CallSession::State::Paused) {
186 187 188 189 190 191
		pauseForTransfer();
	}
	MediaSessionParams msp;
	if (params)
		msp = *params;
	else {
192 193 194
		msp.initDefault(getCore(), LinphoneCallOutgoing);
		msp.enableAudio(getCurrentParams()->audioEnabled());
		msp.enableVideo(getCurrentParams()->videoEnabled());
195
	}
196
	lInfo() << "Starting new call to referred address " << getActiveSession()->getReferTo();
197 198
	L_GET_PRIVATE(&msp)->setReferer(getActiveSession());
	L_GET_PRIVATE(getActiveSession())->setReferPending(false);
Ghislain MARY's avatar
Ghislain MARY committed
199
	LinphoneCallParams *lcp = L_GET_C_BACK_PTR(&msp);
200
	LinphoneCall *newCall = linphone_core_invite_with_params(getCore()->getCCore(), getActiveSession()->getReferTo().c_str(), lcp);
201
	if (newCall) {
202 203
		getActiveSession()->getPrivate()->setTransferTarget(Call::toCpp(newCall)->getActiveSession());
		Call::toCpp(newCall)->getActiveSession()->getPrivate()->notifyReferState();
204
	}
205
	return Call::toCpp(newCall)->getSharedFromThis();
206 207
}

208
// =============================================================================
209

210 211
void Call::createPlayer () const{
	mPlayer = linphone_call_build_player((LinphoneCall *)(this->toC()));
212 213 214
}

// -----------------------------------------------------------------------------
215 216
void Call::startRemoteRing () {
	LinphoneCore *lc = getCore()->getCCore();
217 218 219 220
	if (!lc->sound_conf.play_sndcard)
		return;

	MSSndCard *ringCard = lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
Simon Morlat's avatar
Simon Morlat committed
221 222 223 224 225 226
	SalMediaDescription *md = static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->getLocalDesc();
	if (md){
		int maxRate = md->streams[0].max_rate;
		if (maxRate > 0)
			ms_snd_card_set_preferred_sample_rate(ringCard, maxRate);
	}
227
	if (lc->sound_conf.remote_ring) {
228
		ms_snd_card_set_stream_type(ringCard, MS_SND_CARD_STREAM_VOICE);
229 230 231 232
		lc->ringstream = ring_start(lc->factory, lc->sound_conf.remote_ring, 2000, ringCard);
	}
}

233 234
void Call::terminateBecauseOfLostMedia () {
	lInfo() << "Call [" << this << "]: Media connectivity with " << getRemoteAddress()->asString()
235 236
		<< " is lost, call is going to be terminated";
	static_pointer_cast<MediaSession>(getActiveSession())->terminateBecauseOfLostMedia();
237
	getCore()->getPrivate()->getToneManager()->startNamedTone(getActiveSession(), LinphoneToneCallLost);
238 239
}

240
void Call::setInputAudioDevicePrivate(AudioDevice *audioDevice) {
241 242 243 244 245
	if ((audioDevice->getCapabilities() & static_cast<int>(AudioDevice::Capabilities::Record)) == 0) {
		lError() << "Audio device [" << audioDevice << "] doesn't have Record capability";
		return;
	}

246 247
	static_pointer_cast<MediaSession>(getActiveSession())->setInputAudioDevice(audioDevice);

248 249
}

250
void Call::setOutputAudioDevicePrivate(AudioDevice *audioDevice) {
251 252 253 254 255 256
	if ((audioDevice->getCapabilities() & static_cast<int>(AudioDevice::Capabilities::Play)) == 0) {
		lError() << "Audio device [" << audioDevice << "] doesn't have Play capability";
		return;
	}

	RingStream *ringStream = nullptr;
257
	switch (getState()) {
258 259 260
		case CallSession::State::OutgoingRinging:
		case CallSession::State::Pausing:
		case CallSession::State::Paused:
261
			ringStream = getCore()->getCCore()->ringstream;
262 263 264 265 266
			if (ringStream) {
				ring_stream_set_output_ms_snd_card(ringStream, audioDevice->getSoundCard());
			}
			break;
		case CallSession::State::IncomingReceived:
267
			ringStream = linphone_ringtoneplayer_get_stream(getCore()->getCCore()->ringtoneplayer);
268 269 270 271 272 273 274 275 276 277
			if (ringStream) {
				ring_stream_set_output_ms_snd_card(ringStream, audioDevice->getSoundCard());
			}
			break;
		default:
			static_pointer_cast<MediaSession>(getActiveSession())->setOutputAudioDevice(audioDevice);
			break;
	}
}

278 279
// -----------------------------------------------------------------------------

280 281 282 283 284 285
void Call::onAckBeingSent (const shared_ptr<CallSession> &session, LinphoneHeaders *headers) {
	linphone_call_notify_ack_processing(this->toC(), headers, false);
}

void Call::onAckReceived (const shared_ptr<CallSession> &session, LinphoneHeaders *headers) {
	linphone_call_notify_ack_processing(this->toC(), headers, true);
286 287
}

288 289
void Call::onBackgroundTaskToBeStarted (const shared_ptr<CallSession> &session) {
	mBgTask.start(getCore(),30);
290 291
}

292 293
void Call::onBackgroundTaskToBeStopped (const shared_ptr<CallSession> &session) {
	mBgTask.stop();
294 295
}

296 297
void Call::onCallSessionAccepting (const std::shared_ptr<CallSession> &session) {
	accept();
298 299
}

300
void Call::onCallSessionEarlyFailed (const shared_ptr<CallSession> &session, LinphoneErrorInfo *ei) {
Ghislain MARY's avatar
Ghislain MARY committed
301
	LinphoneCallLog *log = session->getLog();
302
	linphone_core_report_early_failed_call(getCore()->getCCore(),
Ghislain MARY's avatar
Ghislain MARY committed
303
		linphone_call_log_get_dir(log),
304 305
		linphone_address_clone(linphone_call_log_get_from_address(log)),
		linphone_address_clone(linphone_call_log_get_to_address(log)),
306 307
		ei,
		log->call_id);
308
	linphone_call_unref(this->toC());
Ghislain MARY's avatar
Ghislain MARY committed
309 310
}

311 312
void Call::onCallSessionSetReleased (const shared_ptr<CallSession> &session) {
	linphone_call_unref(this->toC());
313 314
}

315 316
void Call::onCallSessionSetTerminated (const shared_ptr<CallSession> &session) {
	LinphoneCore *core = getCore()->getCCore();
317
	
318
	if (getSharedFromThis() == getCore()->getCurrentCall()) {
319
		lInfo() << "Resetting the current call";
320
		getCore()->getPrivate()->setCurrentCall(nullptr);
321
	}
322
	if (getCore()->getPrivate()->removeCall(getSharedFromThis()) != 0)
323
		lError() << "Could not remove the call from the list!!!";
324
#if 0
325 326
	if (mChatRoom)
		linphone_chat_room_set_call(mChatRoom, nullptr);
327
#endif // if 0
328
	if (!getCore()->getPrivate()->hasCalls())
329
		ms_bandwidth_controller_reset_state(core->bw_controller);
330 331
}

332
void Call::onCallSessionStartReferred (const shared_ptr<CallSession> &session) {
333 334 335
	startReferredCall(nullptr);
}

Andrea Gianarda's avatar
Andrea Gianarda committed
336 337 338 339 340 341 342 343 344 345 346
void Call::removeFromConference(const Address & remoteContactAddress) {
	if (getConference()) {
		// Check if the request was sent by the focus
		ConferenceId remoteConferenceId = ConferenceId(remoteContactAddress, getLocalAddress());
		shared_ptr<MediaConference::Conference> conference = getCore()->findAudioVideoConference(remoteConferenceId, false);

		// If conference is found, start termination
		// In the case of a local conference, the following lines wil trigger the deletion of the remote conference created for every call added to the local conference
		if (conference) {
			conference->setState(ConferenceInterface::State::TerminationPending);
			setConference(nullptr);
347
			setConferenceId("");
Andrea Gianarda's avatar
Andrea Gianarda committed
348 349 350 351 352 353 354 355 356
		}
	}
}

void Call::exitFromConference (const shared_ptr<CallSession> &session) {
	if (isInConference()) {
		// Remove participant from local conference
		if (getConference()) {
			lInfo() << "Removing terminated call (local addres " << getLocalAddress().asString() << " remote address " << getRemoteAddress()->asString() << ") from LinphoneConference " << getConference();
357
			MediaConference::Conference::toCpp(getConference())->removeParticipant(getSharedFromThis());
Andrea Gianarda's avatar
Andrea Gianarda committed
358 359 360 361 362 363 364 365 366 367 368 369 370 371
		}
	} else {
		// Searching remote conference to terminate it
		if (session->getPrivate()->getOp() && session->getPrivate()->getOp()->getRemoteContactAddress()) {
			char * remoteContactAddressStr = sal_address_as_string(session->getPrivate()->getOp()->getRemoteContactAddress());
			Address remoteContactAddress(remoteContactAddressStr);
			ms_free(remoteContactAddressStr);

			removeFromConference(remoteContactAddress);
		}
	}
	setConference (nullptr);
}

372 373 374
void Call::onCallSessionStateChanged (const shared_ptr<CallSession> &session, CallSession::State state, const string &message) {
	getCore()->getPrivate()->getToneManager()->update(session);
	LinphoneCore *lc = getCore()->getCCore();
Andrea Gianarda's avatar
Andrea Gianarda committed
375 376

	switch(state) {
377 378
		case CallSession::State::OutgoingInit:
		case CallSession::State::IncomingReceived:
379 380 381
			getPlatformHelpers(lc)->acquireWifiLock();
			getPlatformHelpers(lc)->acquireMcastLock();
			getPlatformHelpers(lc)->acquireCpuLock();
382 383 384
			if (linphone_core_get_calls_nb(lc) == 1) {
				linphone_core_notify_first_call_started(lc);
			}
385 386
			break;
		case CallSession::State::Released:
387 388 389
			getPlatformHelpers(lc)->releaseWifiLock();
			getPlatformHelpers(lc)->releaseMcastLock();
			getPlatformHelpers(lc)->releaseCpuLock();
Andrea Gianarda's avatar
Andrea Gianarda committed
390 391 392 393

			// Terminating or removing participant from conference after receiving the 200 OK of the BYE
			exitFromConference(session);

394
			break;
Andrea Gianarda's avatar
Andrea Gianarda committed
395 396 397 398 399 400 401 402 403 404 405
		case CallSession::State::Pausing:
		case CallSession::State::Paused:
			break;
		case CallSession::State::PausedByRemote:
		{
			// If it is not in a conference, the remote conference must be terminated if it exists
			if (session->getPrivate()->getOp() && session->getPrivate()->getOp()->getRemoteContactAddress()) {
				char * remoteContactAddressStr = sal_address_as_string(session->getPrivate()->getOp()->getRemoteContactAddress());
				Address remoteContactAddress(remoteContactAddressStr);
				ms_free(remoteContactAddressStr);

406 407 408 409 410 411
				// As the call is about to exit the conference, the contact address is missing the conference ID as well as isfocus parameter
				if (!remoteContactAddress.hasUriParam("conf-id")) {
					if (getConferenceId().empty() == false) {
						remoteContactAddress.setUriParam("conf-id", getConferenceId());
					}
				}
Andrea Gianarda's avatar
Andrea Gianarda committed
412 413 414 415 416 417 418
				if (!remoteContactAddress.hasParam("isfocus")) {
					remoteContactAddress.setParam("isfocus");
					removeFromConference(remoteContactAddress);
				}
			}
		}
		break;
419
		case CallSession::State::Error:
Andrea Gianarda's avatar
Andrea Gianarda committed
420 421 422 423
			// Exit call from conference if an error occurred
			exitFromConference(session);
		BCTBX_NO_BREAK; // No break because a notification of last call ended may also be issued if the last remainign call errors out
		case CallSession::State::End:
424 425 426
			if (linphone_core_get_calls_nb(lc) == 0) {
				linphone_core_notify_last_call_ended(lc);
			}
Andrea Gianarda's avatar
Andrea Gianarda committed
427 428 429 430 431 432 433 434 435 436 437 438 439
		break;
		case CallSession::State::UpdatedByRemote:
		{
			if (session->getPrivate()->getOp() && session->getPrivate()->getOp()->getRemoteContactAddress()) {
				char * remoteContactAddressStr = sal_address_as_string(session->getPrivate()->getOp()->getRemoteContactAddress());
				Address remoteContactAddress(remoteContactAddressStr);
				ms_free(remoteContactAddressStr);

				// Check if the request was sent by the focus
				if (remoteContactAddress.hasParam("isfocus")) {
					ConferenceId remoteConferenceId = ConferenceId(remoteContactAddress, getLocalAddress());

					shared_ptr<MediaConference::Conference> conference = getCore()->findAudioVideoConference(remoteConferenceId, false);
440
					if ((conference == nullptr) && (getCore()->getCCore()->conf_ctx == nullptr)) {
Andrea Gianarda's avatar
Andrea Gianarda committed
441 442 443
						// It is expected that the core of the remote conference is the participant one
						shared_ptr<MediaConference::RemoteConference> remoteConf = std::shared_ptr<MediaConference::RemoteConference>(new MediaConference::RemoteConference(getCore(), getSharedFromThis(), remoteConferenceId, nullptr, ConferenceParams::create(getCore()->getCCore())), [](MediaConference::RemoteConference * c){c->unref();});
						setConference(remoteConf->toC());
444 445 446 447 448 449

						// Record conf-id to be used later when terminating the remote conference
						if (remoteContactAddress.hasUriParam("conf-id")) {
							setConferenceId(remoteContactAddress.getUriParamValue("conf-id"));
						}

Andrea Gianarda's avatar
Andrea Gianarda committed
450 451
					}
				} else if (getConference()) {
452 453 454 455 456 457
					// As the call is about to exit the conference, the contact address is missing the conference ID as well as isfocus parameter
					if (!remoteContactAddress.hasUriParam("conf-id")) {
						if (getConferenceId().empty() == false) {
							remoteContactAddress.setUriParam("conf-id", getConferenceId());
						}
					}
Andrea Gianarda's avatar
Andrea Gianarda committed
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
					if (!remoteContactAddress.hasParam("isfocus")) {
						remoteContactAddress.setParam("isfocus");
						removeFromConference(remoteContactAddress);
					}
				}
			}

		}
		break;
		case CallSession::State::StreamsRunning:
		{

			// Try to add device to local conference
			if (getConference() && isInConference()) {
				MediaConference::Conference::toCpp(getConference())->addParticipantDevice(getSharedFromThis());
			}

			if (session->getPrivate()->getOp() && session->getPrivate()->getOp()->getRemoteContactAddress()) {
				char * remoteContactAddressStr = sal_address_as_string(session->getPrivate()->getOp()->getRemoteContactAddress());
				Address remoteContactAddress(remoteContactAddressStr);
				ms_free(remoteContactAddressStr);

				// Check if the request was sent by the focus
				if (remoteContactAddress.hasParam("isfocus")) {
					ConferenceId remoteConferenceId = ConferenceId(remoteContactAddress, getLocalAddress());
					shared_ptr<MediaConference::Conference> conference = getCore()->findAudioVideoConference(remoteConferenceId, false);
					shared_ptr<MediaConference::RemoteConference> remoteConf = nullptr;
					// Create remote conference if no conference with the expected ID is found in the database
					if (conference == nullptr) {
						// It is expected that the core of the remote conference is the participant one
						remoteConf = std::shared_ptr<MediaConference::RemoteConference>(new MediaConference::RemoteConference(getCore(), getSharedFromThis(), remoteConferenceId, nullptr, ConferenceParams::create(getCore()->getCCore())), [](MediaConference::RemoteConference * c){c->unref();});
						setConference(remoteConf->toC());
490 491 492 493 494 495

						// Record conf-id to be used later when terminating the remote conference
						if (remoteContactAddress.hasUriParam("conf-id")) {
							setConferenceId(remoteContactAddress.getUriParamValue("conf-id"));
						}

Andrea Gianarda's avatar
Andrea Gianarda committed
496 497 498 499 500 501 502
					} else {
						remoteConf = static_pointer_cast<MediaConference::RemoteConference>(conference);
					}
				}
			}
		}
		break;
503 504 505
		default:
			break;
	}
506
	linphone_call_notify_state_changed(this->toC(), static_cast<LinphoneCallState>(state), message.c_str());
507 508
}

509 510
void Call::onCallSessionTransferStateChanged (const shared_ptr<CallSession> &session, CallSession::State state) {
	linphone_call_notify_transfer_state_changed(this->toC(), static_cast<LinphoneCallState>(state));
511 512
}

513 514 515
void Call::onCheckForAcceptation (const shared_ptr<CallSession> &session) {
	list<shared_ptr<Call>> calls = getCore()->getCalls();
	shared_ptr<Call> currentCall = getSharedFromThis();
516 517 518 519
	for (const auto &call : calls) {
		if (call == currentCall)
			continue;
		switch (call->getState()) {
520 521 522 523
			case CallSession::State::OutgoingInit:
			case CallSession::State::OutgoingProgress:
			case CallSession::State::OutgoingRinging:
			case CallSession::State::OutgoingEarlyMedia:
524 525 526
				lInfo() << "Already existing call [" << call << "] in state [" << Utils::toString(call->getState())
					<< "], canceling it before accepting new call [" << currentCall << "]";
				call->terminate();
527 528
				break;
			default:
529
				break; // Nothing to do
530 531 532 533
		}
	}
}

534 535
void Call::onDtmfReceived (const shared_ptr<CallSession> &session, char dtmf) {
	linphone_call_notify_dtmf_received(this->toC(), dtmf);
Ghislain MARY's avatar
Ghislain MARY committed
536 537
}

538
void Call::onIncomingCallSessionNotified (const shared_ptr<CallSession> &session) {
539
	/* The call is acceptable so we can now add it to our list */
540
	getCore()->getPrivate()->addCall(getSharedFromThis());
541 542
}

543 544 545
void Call::onIncomingCallSessionStarted (const shared_ptr<CallSession> &session) {
	if (linphone_core_get_calls_nb(getCore()->getCCore()) == 1 && !isInConference()) {
		L_GET_PRIVATE_FROM_C_OBJECT(getCore()->getCCore())->setCurrentCall(getSharedFromThis());
Paul Cartier's avatar
Paul Cartier committed
546
	}
547
	getCore()->getPrivate()->getToneManager()->startRingtone(session);
548 549
}

550
void Call::onIncomingCallSessionTimeoutCheck (const shared_ptr<CallSession> &session, int elapsed, bool oneSecondElapsed) {
551 552
	if (oneSecondElapsed)
		lInfo() << "Incoming call ringing for " << elapsed << " seconds";
553 554 555
	if (elapsed > getCore()->getCCore()->sip_conf.inc_timeout) {
		lInfo() << "Incoming call timeout (" << getCore()->getCCore()->sip_conf.inc_timeout << ")";
		auto config = linphone_core_get_config(getCore()->getCCore());
556 557
		int statusCode = linphone_config_get_int(config, "sip", "inc_timeout_status_code", 486);
		getActiveSession()->declineNotAnswered(linphone_error_code_to_reason(statusCode));
558
	}
559 560
}

561 562 563 564 565 566 567 568 569 570 571 572
void Call::onPushCallSessionTimeoutCheck (const std::shared_ptr<CallSession> &session, int elapsed) {
	if (elapsed > getCore()->getCCore()->sip_conf.push_incoming_call_timeout) {
		lInfo() << "Push incoming call timeout (" << getCore()->getCCore()->sip_conf.push_incoming_call_timeout << ")";
		auto config = linphone_core_get_config(getCore()->getCCore());
		int statusCode = linphone_config_get_int(config, "sip", "push_incoming_call_timeout_status_code", 410); //LinphoneReasonGone
		getActiveSession()->decline(linphone_error_code_to_reason(statusCode));
		getActiveSession()->getPrivate()->setState(LinphonePrivate::CallSession::State::Released, "Call released");
	}
}

void Call::onInfoReceived (const shared_ptr<CallSession> &session, const LinphoneInfoMessage *im) {
	linphone_call_notify_info_message_received(this->toC(), im);
573 574
}

575
void Call::onLossOfMediaDetected (const shared_ptr<CallSession> &session) {
Simon Morlat's avatar
Simon Morlat committed
576
	terminateBecauseOfLostMedia();
577 578
}

579 580
void Call::onEncryptionChanged (const shared_ptr<CallSession> &session, bool activated, const string &authToken) {
	linphone_call_notify_encryption_changed(this->toC(), activated, authToken.empty() ? nullptr : authToken.c_str());
581 582
}

583 584
void Call::onCallSessionStateChangedForReporting (const shared_ptr<CallSession> &session) {
	linphone_reporting_call_state_updated(this->toC());
Ghislain MARY's avatar
Ghislain MARY committed
585 586
}

587 588
void Call::onRtcpUpdateForReporting (const shared_ptr<CallSession> &session, SalStreamType type) {
	linphone_reporting_on_rtcp_update(this->toC(), type);
Ghislain MARY's avatar
Ghislain MARY committed
589 590
}

591 592
void Call::onStatsUpdated (const shared_ptr<CallSession> &session, const LinphoneCallStats *stats) {
	linphone_call_notify_stats_updated(this->toC(), stats);
593 594
}

595 596
void Call::onUpdateMediaInfoForReporting (const shared_ptr<CallSession> &session, int statsType) {
	linphone_reporting_update_media_info(this->toC(), statsType);
Ghislain MARY's avatar
Ghislain MARY committed
597 598
}

599 600
void Call::onResetCurrentSession (const shared_ptr<CallSession> &session) {
	getCore()->getPrivate()->setCurrentCall(nullptr);
601 602
}

603 604
void Call::onSetCurrentSession (const shared_ptr<CallSession> &session) {
	getCore()->getPrivate()->setCurrentCall(getSharedFromThis());
605 606
}

607 608 609 610 611
void Call::onFirstVideoFrameDecoded (const shared_ptr<CallSession> &session) {
	if (mNextVideoFrameDecoded._func) {
		mNextVideoFrameDecoded._func(this->toC(), mNextVideoFrameDecoded._user_data);
		mNextVideoFrameDecoded._func = nullptr;
		mNextVideoFrameDecoded._user_data = nullptr;
612
	}
613
	linphone_call_notify_next_video_frame_decoded(this->toC());
614 615
}

616
void Call::onResetFirstVideoFrameDecoded (const shared_ptr<CallSession> &session) {
617
	/*we are called here by the MediaSession when the stream start to know whether there is the deprecated nextVideoFrameDecoded callback set,
Simon Morlat's avatar
Simon Morlat committed
618 619
	 * so that we can request the notification of the next frame decoded.*/
#ifdef VIDEO_ENABLED
620
	if (mNextVideoFrameDecoded._func)
Simon Morlat's avatar
Simon Morlat committed
621 622 623 624
		requestNotifyNextVideoFrameDecoded();
#endif // ifdef VIDEO_ENABLED
}

625
void Call::requestNotifyNextVideoFrameDecoded(){
Simon Morlat's avatar
Simon Morlat committed
626
	static_pointer_cast<MediaSession>(getActiveSession())->requestNotifyNextVideoFrameDecoded();
627
}
628

629 630
void Call::onCameraNotWorking (const std::shared_ptr<CallSession> &session, const char *camera_name) {
	linphone_call_notify_camera_not_working(this->toC(), camera_name);
631 632
}

633 634 635 636
bool Call::areSoundResourcesAvailable (const shared_ptr<CallSession> &session) {
	LinphoneCore *lc = getCore()->getCCore();
	shared_ptr<Call> currentCall = getCore()->getCurrentCall();
	return !linphone_core_is_in_conference(lc) && (!currentCall || (currentCall == getSharedFromThis()));
Ghislain MARY's avatar
Ghislain MARY committed
637 638
}

639 640
bool Call::isPlayingRingbackTone (const shared_ptr<CallSession> &session) {
	return mPlayingRingbackTone;
641 642
}

Andrea Gianarda's avatar
Andrea Gianarda committed
643 644 645 646
LinphoneConference * Call::getCallSessionConference (const shared_ptr<CallSession> &session) {
	return getConference();
}

647
void Call::onRealTimeTextCharacterReceived (const shared_ptr<CallSession> &session, RealtimeTextReceivedCharacter *data) {
648 649
	shared_ptr<AbstractChatRoom> chatRoom = getChatRoom();
	if (chatRoom) {
650
		chatRoom->getPrivate()->realtimeTextReceived(data->character, getSharedFromThis());
651 652 653
	} else {
		lError()<<"CallPrivate::onRealTimeTextCharacterReceived: no chatroom.";
	}
Ghislain MARY's avatar
Ghislain MARY committed
654 655
}

656 657
void Call::onTmmbrReceived (const shared_ptr<CallSession> &session, int streamIndex, int tmmbr) {
	linphone_call_notify_tmmbr_received(this->toC(), streamIndex, tmmbr);
Mickaël Turnel's avatar
Mickaël Turnel committed
658 659
}

660
void Call::onSnapshotTaken(const shared_ptr<CallSession> &session, const char *file_path) {
DanmeiChen's avatar
DanmeiChen committed
661
	linphone_call_notify_snapshot_taken(this->toC(), file_path);
662 663
}

664 665
// =============================================================================

666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
Call::Call (
	shared_ptr<Core> core,
	LinphoneCallDir direction,
	const Address &from,
	const Address &to,
	LinphoneProxyConfig *cfg,
	SalCallOp *op,
	const MediaSessionParams *msp
) : CoreAccessor(core) {
	mNextVideoFrameDecoded._func = nullptr;
	mNextVideoFrameDecoded._user_data = nullptr;

	mBgTask.setName("Liblinphone call notification");

	//create session
Andrea Gianarda's avatar
Andrea Gianarda committed
681 682 683
	mParticipant = Participant::create(nullptr, IdentityAddress((direction == LinphoneCallIncoming) ? to : from));
	mParticipant->createSession(getCore(), msp, TRUE, this);
	mParticipant->getSession()->configure(direction, cfg, op, from, to);
684 685 686 687 688 689 690 691 692 693 694 695
}

Call::Call (
	std::shared_ptr<Core> core,
	LinphoneCallDir direction,
	const string &callid
): CoreAccessor(core) {
	mNextVideoFrameDecoded._func = nullptr;
	mNextVideoFrameDecoded._user_data = nullptr;

	mBgTask.setName("Liblinphone call notification");

Andrea Gianarda's avatar
Andrea Gianarda committed
696 697 698
	mParticipant = Participant::create();
	mParticipant->createSession(getCore(), nullptr, TRUE, this);
	mParticipant->getSession()->configure(direction, callid);
699 700 701 702 703 704 705 706 707
}

Call::~Call () {
	auto session = getActiveSession();
	if (session)
		session->getPrivate()->setCallSessionListener(nullptr);
	
	bctbx_list_free_with_data(mCallbacks, (bctbx_list_free_func)linphone_call_cbs_unref);
}
708

709 710 711 712 713 714 715 716 717
void Call::configure (
	LinphoneCallDir direction,
	const Address &from,
	const Address &to,
	LinphoneProxyConfig *cfg,
	SalCallOp *op,
	const MediaSessionParams *msp
) {
	mParticipant->configure(nullptr, IdentityAddress((direction == LinphoneCallIncoming) ? to : from));
Andrea Gianarda's avatar
Andrea Gianarda committed
718
	mParticipant->getSession()->configure(direction, cfg, op, from, to);
719 720
}

721 722 723 724 725
bool Call::isOpConfigured () const {
	return getActiveSession()->isOpConfigured();
}

// =============================================================================
726

727
LinphoneStatus Call::accept (const MediaSessionParams *msp) {
728
	return static_pointer_cast<MediaSession>(getActiveSession())->accept(msp);
729 730
}

731
LinphoneStatus Call::acceptEarlyMedia (const MediaSessionParams *msp) {
732
	return static_pointer_cast<MediaSession>(getActiveSession())->acceptEarlyMedia(msp);
733 734
}

735
LinphoneStatus Call::acceptUpdate (const MediaSessionParams *msp) {
736
	return static_pointer_cast<MediaSession>(getActiveSession())->acceptUpdate(msp);
737 738
}

Ghislain MARY's avatar
Ghislain MARY committed
739
void Call::cancelDtmfs () {
740
	static_pointer_cast<MediaSession>(getActiveSession())->cancelDtmfs();
Ghislain MARY's avatar
Ghislain MARY committed
741 742
}

743
LinphoneStatus Call::decline (LinphoneReason reason) {
744
	return getActiveSession()->decline(reason);
745 746 747
}

LinphoneStatus Call::decline (const LinphoneErrorInfo *ei) {
748
	return getActiveSession()->decline(ei);
749 750
}

751
LinphoneStatus Call::deferUpdate () {
752
	return getActiveSession()->deferUpdate();
753 754
}

755
bool Call::hasTransferPending () const {
756
	return getActiveSession()->hasTransferPending();
757 758
}

Ghislain MARY's avatar
Ghislain MARY committed
759
void Call::oglRender () const {
760
	static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->oglRender();
Ghislain MARY's avatar
Ghislain MARY committed
761 762
}

Andrea Gianarda's avatar
Andrea Gianarda committed
763 764 765 766
LinphoneStatus Call::pauseFromConference () {
	return static_pointer_cast<MediaSession>(getActiveSession())->pauseFromConference();
}

767
LinphoneStatus Call::pause () {
768
	return static_pointer_cast<MediaSession>(getActiveSession())->pause();
769 770
}

771 772 773 774
bool Call::canSoundResourcesBeFreed () const {
	return static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->canSoundResourcesBeFreed();
}

775
LinphoneStatus Call::redirect (const string &redirectUri) {
776
	return getActiveSession()->redirect(redirectUri);
777 778
}

Sylvain Berfini's avatar
Sylvain Berfini committed
779 780 781 782
LinphoneStatus Call::redirect (const Address &redirectAddress) {
	return getActiveSession()->redirect(redirectAddress);
}

783
LinphoneStatus Call::resume () {
784
	return static_pointer_cast<MediaSession>(getActiveSession())->resume();
785 786
}

Ghislain MARY's avatar
Ghislain MARY committed
787
LinphoneStatus Call::sendDtmf (char dtmf) {
788
	return static_pointer_cast<MediaSession>(getActiveSession())->sendDtmf(dtmf);
Ghislain MARY's avatar
Ghislain MARY committed
789 790
}

791
LinphoneStatus Call::sendDtmfs (const string &dtmfs) {
792
	return static_pointer_cast<MediaSession>(getActiveSession())->sendDtmfs(dtmfs);
Ghislain MARY's avatar
Ghislain MARY committed
793 794
}

795
void Call::sendVfuRequest () {
796
	static_pointer_cast<MediaSession>(getActiveSession())->sendVfuRequest();
797 798 799
}

void Call::startRecording () {
800
	static_pointer_cast<MediaSession>(getActiveSession())->startRecording();
801 802 803
}

void Call::stopRecording () {
804
	static_pointer_cast<MediaSession>(getActiveSession())->stopRecording();
805 806
}

807
bool Call::isRecording () {
808
	return static_pointer_cast<MediaSession>(getActiveSession())->isRecording();
809 810
}

Ronan's avatar
Ronan committed
811
LinphoneStatus Call::takePreviewSnapshot (const string &file) {
812
	return static_pointer_cast<MediaSession>(getActiveSession())->takePreviewSnapshot(file);
813 814
}

Ronan's avatar
Ronan committed
815
LinphoneStatus Call::takeVideoSnapshot (const string &file) {
816
	return static_pointer_cast<MediaSession>(getActiveSession())->takeVideoSnapshot(file);
817 818 819
}

LinphoneStatus Call::terminate (const LinphoneErrorInfo *ei) {
820
	return getActiveSession()->terminate(ei);
821 822
}

823
LinphoneStatus Call::transfer (const shared_ptr<Call> &dest) {
824
	return getActiveSession()->transfer(dest->getActiveSession());
825 826 827
}

LinphoneStatus Call::transfer (const string &dest) {
828
	return getActiveSession()->transfer(dest);
829 830
}

Sylvain Berfini's avatar
Sylvain Berfini committed
831 832 833 834
LinphoneStatus Call::transfer (const Address &dest) {
	return getActiveSession()->transfer(dest);
}

Andrea Gianarda's avatar
Andrea Gianarda committed
835 836 837 838
LinphoneStatus Call::updateFromConference (const MediaSessionParams *msp) {
	return static_pointer_cast<MediaSession>(getActiveSession())->updateFromConference(msp);
}

839
LinphoneStatus Call::update (const MediaSessionParams *msp) {
840
	return static_pointer_cast<MediaSession>(getActiveSession())->update(msp);
841 842 843
}

void Call::zoomVideo (float zoomFactor, float *cx, float *cy) {
844 845 846 847
	zoomVideo(zoomFactor, *cx, *cy);
}

void Call::zoomVideo (float zoomFactor, float cx, float cy) {
848
	static_pointer_cast<MediaSession>(getActiveSession())->zoomVideo(zoomFactor, cx, cy);
849 850 851 852
}

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

853
bool Call::cameraEnabled () const {