/* * call.cpp * Copyright (C) 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 3 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, see . */ #include "call-p.h" #include "conference/local-conference.h" #include "conference/participant-p.h" #include "conference/remote-conference.h" #include "conference/session/media-session-p.h" #include "logger/logger.h" // ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE CallPrivate::CallPrivate ( LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp ) : lcall(call), core(core) { nextVideoFrameDecoded._func = nullptr; nextVideoFrameDecoded._user_data = nullptr; } CallPrivate::~CallPrivate () { if (conference) delete conference; } // ----------------------------------------------------------------------------- shared_ptr CallPrivate::getActiveSession () const { return conference->getActiveParticipant()->getPrivate()->getSession(); } bool CallPrivate::getAudioMuted () const { return static_cast(getActiveSession().get())->getPrivate()->getAudioMuted(); } LinphoneProxyConfig *CallPrivate::getDestProxy () const { return getActiveSession()->getPrivate()->getDestProxy(); } IceSession *CallPrivate::getIceSession () const { return static_cast(getActiveSession().get())->getPrivate()->getIceSession(); } MediaStream *CallPrivate::getMediaStream (LinphoneStreamType type) const { return static_cast(getActiveSession().get())->getPrivate()->getMediaStream(type); } SalOp *CallPrivate::getOp () const { return getActiveSession()->getPrivate()->getOp(); } void CallPrivate::setAudioMuted (bool value) { static_cast(getActiveSession().get())->getPrivate()->setAudioMuted(value); } // ----------------------------------------------------------------------------- void CallPrivate::initiateIncoming () { getActiveSession()->initiateIncoming(); } bool CallPrivate::initiateOutgoing () { return getActiveSession()->initiateOutgoing(); } void CallPrivate::iterate (time_t currentRealTime, bool oneSecondElapsed) { getActiveSession()->iterate(currentRealTime, oneSecondElapsed); } void CallPrivate::startIncomingNotification () { getActiveSession()->startIncomingNotification(); } int CallPrivate::startInvite (const Address *destination) { return getActiveSession()->startInvite(destination, ""); } // ----------------------------------------------------------------------------- void CallPrivate::onAckBeingSent (LinphoneHeaders *headers) { if (lcall) linphone_call_notify_ack_processing(lcall, headers, false); } void CallPrivate::onAckReceived (LinphoneHeaders *headers) { if (lcall) linphone_call_notify_ack_processing(lcall, headers, true); } void CallPrivate::onCallSetReleased () { if (lcall) linphone_call_unref(lcall); } void CallPrivate::onCallSetTerminated () { if (lcall) { if (lcall == core->current_call) { lInfo() << "Resetting the current call"; core->current_call = nullptr; } if (linphone_core_del_call(core, lcall) != 0) lError() << "Could not remove the call from the list!!!"; #if 0 if (core->conf_ctx) linphone_conference_on_call_terminating(core->conf_ctx, lcall); if (lcall->ringing_beep) { linphone_core_stop_dtmf(core); lcall->ringing_beep = false; } if (lcall->chat_room) linphone_chat_room_set_call(lcall->chat_room, nullptr); #endif // if 0 if (!core->calls) ms_bandwidth_controller_reset_state(core->bw_controller); } } void CallPrivate::onCallStateChanged (LinphoneCallState state, const string &message) { if (lcall) linphone_call_notify_state_changed(lcall, state, message.c_str()); } void CallPrivate::onCheckForAcceptation () { bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(core)); for (bctbx_list_t *it = copy; it != nullptr; it = bctbx_list_next(it)) { LinphoneCall *call = reinterpret_cast(bctbx_list_get_data(it)); if (call == lcall) continue; switch (linphone_call_get_state(call)) { case LinphoneCallOutgoingInit: case LinphoneCallOutgoingProgress: case LinphoneCallOutgoingRinging: case LinphoneCallOutgoingEarlyMedia: lInfo() << "Already existing call [" << call << "] in state [" << linphone_call_state_to_string(linphone_call_get_state(call)) << "], canceling it before accepting new call [" << lcall << "]"; linphone_call_terminate(call); break; default: break; /* Nothing to do */ } } bctbx_list_free(copy); } void CallPrivate::onIncomingCallStarted () { if (lcall) linphone_core_notify_incoming_call(core, lcall); } void CallPrivate::onIncomingCallToBeAdded () { if (lcall) /* The call is acceptable so we can now add it to our list */ linphone_core_add_call(core, lcall); } void CallPrivate::onEncryptionChanged (bool activated, const string &authToken) { if (lcall) linphone_call_notify_encryption_changed(lcall, activated, authToken.empty() ? nullptr : authToken.c_str()); } void CallPrivate::onStatsUpdated (const LinphoneCallStats *stats) { if (lcall) linphone_call_notify_stats_updated(lcall, stats); } void CallPrivate::onResetCurrentCall () { core->current_call = nullptr; } void CallPrivate::onSetCurrentCall () { if (lcall) core->current_call = lcall; } void CallPrivate::onFirstVideoFrameDecoded () { if (lcall && nextVideoFrameDecoded._func) { nextVideoFrameDecoded._func(lcall, nextVideoFrameDecoded._user_data); nextVideoFrameDecoded._func = nullptr; nextVideoFrameDecoded._user_data = nullptr; } } void CallPrivate::onResetFirstVideoFrameDecoded () { #ifdef VIDEO_ENABLED if (lcall && nextVideoFrameDecoded._func) static_cast(getActiveSession().get())->resetFirstVideoFrameDecoded(); #endif // ifdef VIDEO_ENABLED } // ============================================================================= Call::Call ( LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp ) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { L_D(); const Address *myAddress = (direction == LinphoneCallIncoming) ? &to : &from; string confType = lp_config_get_string(linphone_core_get_config(core), "misc", "conference_type", "local"); if (confType == "remote") { d->conference = new RemoteConference(core, *myAddress, d); } else { d->conference = new LocalConference(core, *myAddress, d); } const Address *remoteAddress = (direction == LinphoneCallIncoming) ? &from : &to; shared_ptr participant = d->conference->addParticipant(*remoteAddress, msp, true); participant->getPrivate()->getSession()->configure(direction, cfg, op, from, to); } // ----------------------------------------------------------------------------- LinphoneStatus Call::accept (const MediaSessionParams *msp) { L_D(); return static_cast(d->getActiveSession().get())->accept(msp); } LinphoneStatus Call::acceptEarlyMedia (const MediaSessionParams *msp) { L_D(); return static_cast(d->getActiveSession().get())->acceptEarlyMedia(msp); } LinphoneStatus Call::acceptUpdate (const MediaSessionParams *msp) { L_D(); return static_cast(d->getActiveSession().get())->acceptUpdate(msp); } LinphoneStatus Call::decline (LinphoneReason reason) { L_D(); return d->getActiveSession()->decline(reason); } LinphoneStatus Call::decline (const LinphoneErrorInfo *ei) { L_D(); return d->getActiveSession()->decline(ei); } LinphoneStatus Call::pause () { L_D(); return static_cast(d->getActiveSession().get())->pause(); } LinphoneStatus Call::resume () { L_D(); return static_cast(d->getActiveSession().get())->resume(); } void Call::sendVfuRequest () { L_D(); static_cast(d->getActiveSession().get())->sendVfuRequest(); } void Call::startRecording () { L_D(); static_cast(d->getActiveSession().get())->startRecording(); } void Call::stopRecording () { L_D(); static_cast(d->getActiveSession().get())->stopRecording(); } LinphoneStatus Call::takePreviewSnapshot (const string &file) { L_D(); return static_cast(d->getActiveSession().get())->takePreviewSnapshot(file); } LinphoneStatus Call::takeVideoSnapshot (const string &file) { L_D(); return static_cast(d->getActiveSession().get())->takeVideoSnapshot(file); } LinphoneStatus Call::terminate (const LinphoneErrorInfo *ei) { L_D(); return d->getActiveSession()->terminate(ei); } LinphoneStatus Call::update (const MediaSessionParams *msp) { L_D(); return static_cast(d->getActiveSession().get())->update(msp); } void Call::zoomVideo (float zoomFactor, float *cx, float *cy) { L_D(); static_cast(d->getActiveSession().get())->zoomVideo(zoomFactor, cx, cy); } // ----------------------------------------------------------------------------- bool Call::cameraEnabled () const { L_D(); return static_cast(d->getActiveSession().get())->cameraEnabled(); } bool Call::echoCancellationEnabled () const { L_D(); return static_cast(d->getActiveSession().get())->echoCancellationEnabled(); } bool Call::echoLimiterEnabled () const { L_D(); return static_cast(d->getActiveSession().get())->echoLimiterEnabled(); } void Call::enableCamera (bool value) { L_D(); static_cast(d->getActiveSession().get())->enableCamera(value); } void Call::enableEchoCancellation (bool value) { L_D(); static_cast(d->getActiveSession().get())->enableEchoCancellation(value); } void Call::enableEchoLimiter (bool value) { L_D(); static_cast(d->getActiveSession().get())->enableEchoLimiter(value); } bool Call::getAllMuted () const { L_D(); return static_cast(d->getActiveSession().get())->getAllMuted(); } LinphoneCallStats *Call::getAudioStats () const { L_D(); return static_cast(d->getActiveSession().get())->getAudioStats(); } string Call::getAuthenticationToken () const { L_D(); return static_cast(d->getActiveSession().get())->getAuthenticationToken(); } bool Call::getAuthenticationTokenVerified () const { L_D(); return static_cast(d->getActiveSession().get())->getAuthenticationTokenVerified(); } float Call::getAverageQuality () const { L_D(); return static_cast(d->getActiveSession().get())->getAverageQuality(); } LinphoneCore *Call::getCore () const { L_D(); return d->core; } const MediaSessionParams *Call::getCurrentParams () const { L_D(); return static_cast(d->getActiveSession().get())->getCurrentParams(); } float Call::getCurrentQuality () const { L_D(); return static_cast(d->getActiveSession().get())->getCurrentQuality(); } LinphoneCallDir Call::getDirection () const { L_D(); return d->getActiveSession()->getDirection(); } int Call::getDuration () const { L_D(); return d->getActiveSession()->getDuration(); } const LinphoneErrorInfo *Call::getErrorInfo () const { L_D(); return d->getActiveSession()->getErrorInfo(); } LinphoneCallLog *Call::getLog () const { L_D(); return d->getActiveSession()->getLog(); } RtpTransport *Call::getMetaRtcpTransport (int streamIndex) const { L_D(); return static_cast(d->getActiveSession().get())->getMetaRtcpTransport(streamIndex); } RtpTransport *Call::getMetaRtpTransport (int streamIndex) const { L_D(); return static_cast(d->getActiveSession().get())->getMetaRtpTransport(streamIndex); } float Call::getMicrophoneVolumeGain () const { L_D(); return static_cast(d->getActiveSession().get())->getMicrophoneVolumeGain(); } void *Call::getNativeVideoWindowId () const { L_D(); return static_cast(d->getActiveSession().get())->getNativeVideoWindowId(); } const MediaSessionParams *Call::getParams () const { L_D(); return static_cast(d->getActiveSession().get())->getMediaParams(); } float Call::getPlayVolume () const { L_D(); return static_cast(d->getActiveSession().get())->getPlayVolume(); } LinphoneReason Call::getReason () const { L_D(); return d->getActiveSession()->getReason(); } float Call::getRecordVolume () const { L_D(); return static_cast(d->getActiveSession().get())->getRecordVolume(); } const Address &Call::getRemoteAddress () const { L_D(); return d->getActiveSession()->getRemoteAddress(); } string Call::getRemoteAddressAsString () const { L_D(); return d->getActiveSession()->getRemoteAddressAsString(); } string Call::getRemoteContact () const { L_D(); return d->getActiveSession()->getRemoteContact(); } const MediaSessionParams *Call::getRemoteParams () const { L_D(); return static_cast(d->getActiveSession().get())->getRemoteParams(); } float Call::getSpeakerVolumeGain () const { L_D(); return static_cast(d->getActiveSession().get())->getSpeakerVolumeGain(); } LinphoneCallState Call::getState () const { L_D(); return d->getActiveSession()->getState(); } LinphoneCallStats *Call::getStats (LinphoneStreamType type) const { L_D(); return static_cast(d->getActiveSession().get())->getStats(type); } int Call::getStreamCount () const { L_D(); return static_cast(d->getActiveSession().get())->getStreamCount(); } MSFormatType Call::getStreamType (int streamIndex) const { L_D(); return static_cast(d->getActiveSession().get())->getStreamType(streamIndex); } LinphoneCallStats *Call::getTextStats () const { L_D(); return static_cast(d->getActiveSession().get())->getTextStats(); } LinphoneCallStats *Call::getVideoStats () const { L_D(); return static_cast(d->getActiveSession().get())->getVideoStats(); } bool Call::mediaInProgress () const { L_D(); return static_cast(d->getActiveSession().get())->mediaInProgress(); } void Call::setAuthenticationTokenVerified (bool value) { L_D(); static_cast(d->getActiveSession().get())->setAuthenticationTokenVerified(value); } void Call::setMicrophoneVolumeGain (float value) { L_D(); static_cast(d->getActiveSession().get())->setMicrophoneVolumeGain(value); } void Call::setNativeVideoWindowId (void *id) { L_D(); static_cast(d->getActiveSession().get())->setNativeVideoWindowId(id); } void Call::setNextVideoFrameDecodedCallback (LinphoneCallCbFunc cb, void *user_data) { L_D(); d->nextVideoFrameDecoded._func = cb; d->nextVideoFrameDecoded._user_data = user_data; d->onResetFirstVideoFrameDecoded(); } void Call::setSpeakerVolumeGain (float value) { L_D(); static_cast(d->getActiveSession().get())->setSpeakerVolumeGain(value); } LINPHONE_END_NAMESPACE