/* * core-call.cpp * Copyright (C) 2010-2017 Belledonne Communications SARL * * 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. * * 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 * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "core-p.h" #include "call/call-p.h" #include "conference/session/call-session-p.h" #include "logger/logger.h" // TODO: Remove me later. #include "c-wrapper/c-wrapper.h" // ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE int CorePrivate::addCall (const shared_ptr &call) { L_Q(); L_ASSERT(call); if (!canWeAddCall()) return -1; if (!hasCalls()) notifySoundcardUsage(true); calls.push_back(call); linphone_core_notify_call_created(q->getCCore(), L_GET_C_BACK_PTR(call)); return 0; } bool CorePrivate::canWeAddCall () const { L_Q(); if (q->getCallCount() < static_cast(q->getCCore()->max_calls)) return true; lInfo() << "Maximum amount of simultaneous calls reached!"; return false; } bool CorePrivate::inviteReplacesABrokenCall (SalCallOp *op) { CallSession *replacedSession = nullptr; SalCallOp *replacedOp = op->get_replaces(); if (replacedOp) replacedSession = reinterpret_cast(replacedOp->get_user_pointer()); for (const auto &call : calls) { shared_ptr session = call->getPrivate()->getActiveSession(); if (session && ((session->getPrivate()->isBroken() && op->compare_op(session->getPrivate()->getOp())) || ((replacedSession == session.get()) && (strcmp(op->get_from(), replacedOp->get_from()) == 0) && (strcmp(op->get_to(), replacedOp->get_to()) == 0))) ) { session->getPrivate()->replaceOp(op); return true; } } return false; } bool CorePrivate::isAlreadyInCallWithAddress (const Address &addr) const { for (const auto &call : calls) { if (call->getRemoteAddress().weakEqual(addr)) return true; } return false; } void CorePrivate::iterateCalls (time_t currentRealTime, bool oneSecondElapsed) const { for (const auto &call : calls) { call->getPrivate()->iterate(currentRealTime, oneSecondElapsed); } } void CorePrivate::notifySoundcardUsage (bool used) { L_Q(); MSSndCard *card = q->getCCore()->sound_conf.capt_sndcard; if (card && (ms_snd_card_get_capabilities(card) & MS_SND_CARD_CAP_IS_SLOW)) ms_snd_card_set_usage_hint(card, used); } int CorePrivate::removeCall (const shared_ptr &call) { L_ASSERT(call); auto iter = find(calls.begin(), calls.end(), call); if (iter == calls.end()) { lWarning() << "Could not find the call to remove"; return -1; } calls.erase(iter); return 0; } void CorePrivate::unsetVideoWindowId (bool preview, void *id) { #ifdef VIDEO_ENABLED for (const auto &call : calls) { VideoStream *vstream = reinterpret_cast(call->getPrivate()->getMediaStream(LinphoneStreamTypeVideo)); if (vstream) { if (preview) video_stream_set_native_preview_window_id(vstream, id); else video_stream_set_native_window_id(vstream, id); } } #endif } // ============================================================================= bool Core::areSoundResourcesLocked () const { L_D(); for (const auto &call : d->calls) { if (call->mediaInProgress()) return true; switch (call->getState()) { case LinphoneCallOutgoingInit: case LinphoneCallOutgoingProgress: case LinphoneCallOutgoingRinging: case LinphoneCallOutgoingEarlyMedia: case LinphoneCallConnected: case LinphoneCallRefered: case LinphoneCallIncomingEarlyMedia: case LinphoneCallUpdating: lInfo() << "Call " << call << " is locking sound resources"; return true; default: break; } } return false; } shared_ptr Core::getCallByRemoteAddress (const Address &addr) const { L_D(); for (const auto &call : d->calls) { if (call->getRemoteAddress().weakEqual(addr)) return call; } return nullptr; } const list> &Core::getCalls () const { L_D(); return d->calls; } unsigned int Core::getCallCount () const { L_D(); return static_cast(d->calls.size()); } shared_ptr Core::getCurrentCall () const { L_D(); return d->currentCall; } LinphoneStatus Core::pauseAllCalls () { L_D(); for (const auto &call : d->calls) { if ((call->getState() == LinphoneCallStreamsRunning) || (call->getState() == LinphoneCallPausedByRemote)) call->pause(); } return 0; } void Core::soundcardHintCheck () { L_D(); bool noNeedForSound = true; // Check if the remaining calls are paused for (const auto &call : d->calls) { if ((call->getState() != LinphoneCallPausing) && (call->getState() != LinphoneCallPaused) && (call->getState() != LinphoneCallEnd) && (call->getState() != LinphoneCallError)) { noNeedForSound = false; break; } } // If no more calls or all calls are paused, we can free the soundcard LinphoneConfig *config = linphone_core_get_config(L_GET_C_BACK_PTR(this)); bool useRtpIo = !!lp_config_get_int(config, "sound", "rtp_io", FALSE); bool useRtpIoEnableLocalOutput = !!lp_config_get_int(config, "sound", "rtp_io_enable_local_output", FALSE); bool useFiles = L_GET_C_BACK_PTR(getSharedFromThis())->use_files; if ((!d->hasCalls() || noNeedForSound) && (!useFiles && (!useRtpIo || (useRtpIo && useRtpIoEnableLocalOutput)))) { lInfo() << "Notifying soundcard that we don't need it anymore for calls"; d->notifySoundcardUsage(false); } } LinphoneStatus Core::terminateAllCalls () { L_D(); while (!d->calls.empty()) { d->calls.front()->terminate(); } return 0; } LINPHONE_END_NAMESPACE