/* * Copyright (c) 2010-2019 Belledonne Communications SARL. * * This file is part of linphone-android * (see https://www.linphone.org). * * 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 . */ package org.linphone.call; import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import android.widget.Toast; import org.linphone.LinphoneContext; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; import org.linphone.core.Address; import org.linphone.core.Call; import org.linphone.core.CallParams; import org.linphone.core.Core; import org.linphone.core.MediaEncryption; import org.linphone.core.ProxyConfig; import org.linphone.core.tools.Log; import org.linphone.dialer.views.AddressType; import org.linphone.mediastream.Version; import org.linphone.settings.LinphonePreferences; import org.linphone.utils.FileUtils; import org.linphone.utils.LinphoneUtils; /** Handle call updating, reinvites. */ public class CallManager { private Context mContext; private CallActivityInterface mCallInterface; private BandwidthManager mBandwidthManager; public CallManager(Context context) { mContext = context; mBandwidthManager = new BandwidthManager(); } public void destroy() { mBandwidthManager.destroy(); } public void terminateCurrentCallOrConferenceOrAll() { Core core = LinphoneManager.getCore(); Call call = core.getCurrentCall(); if (call != null) { call.terminate(); } else if (core.isInConference()) { core.terminateConference(); } else { core.terminateAllCalls(); } } public void addVideo() { Call call = LinphoneManager.getCore().getCurrentCall(); if (call.getState() == Call.State.End || call.getState() == Call.State.Released) return; if (!call.getCurrentParams().videoEnabled()) { enableCamera(call, true); reinviteWithVideo(); } } public void removeVideo() { Core core = LinphoneManager.getCore(); Call call = core.getCurrentCall(); CallParams params = core.createCallParams(call); params.enableVideo(false); call.update(params); } public void switchCamera() { Core core = LinphoneManager.getCore(); if (core == null) return; String currentDevice = core.getVideoDevice(); Log.i("[Call Manager] Current camera device is " + currentDevice); String[] devices = core.getVideoDevicesList(); for (String d : devices) { if (!d.equals(currentDevice) && !d.equals("StaticImage: Static picture")) { Log.i("[Call Manager] New camera device will be " + d); core.setVideoDevice(d); break; } } Call call = core.getCurrentCall(); if (call == null) { Log.i("[Call Manager] Switching camera while not in call"); return; } call.update(null); } public boolean acceptCall(Call call) { if (call == null) return false; Core core = LinphoneManager.getCore(); CallParams params = core.createCallParams(call); boolean isLowBandwidthConnection = !LinphoneUtils.isHighBandwidthConnection( LinphoneContext.instance().getApplicationContext()); if (params != null) { params.enableLowBandwidth(isLowBandwidthConnection); params.setRecordFile( FileUtils.getCallRecordingFilename(mContext, call.getRemoteAddress())); } else { Log.e("[Call Manager] Could not create call params for call"); return false; } call.acceptWithParams(params); return true; } public void acceptCallUpdate(boolean accept) { Core core = LinphoneManager.getCore(); Call call = core.getCurrentCall(); if (call == null) { return; } CallParams params = core.createCallParams(call); if (accept) { params.enableVideo(true); core.enableVideoCapture(true); core.enableVideoDisplay(true); } call.acceptUpdate(params); } public void inviteAddress(Address address, boolean forceZRTP) { boolean isLowBandwidthConnection = !LinphoneUtils.isHighBandwidthConnection( LinphoneContext.instance().getApplicationContext()); inviteAddress(address, false, isLowBandwidthConnection, forceZRTP); } public void inviteAddress(Address address, boolean videoEnabled, boolean lowBandwidth) { inviteAddress(address, videoEnabled, lowBandwidth, false); } public void newOutgoingCall(AddressType address) { String to = address.getText().toString(); newOutgoingCall(to, address.getDisplayedName()); } public void newOutgoingCall(String to, String displayName) { if (to == null) return; // If to is only a username, try to find the contact to get an alias if existing if (!to.startsWith("sip:") || !to.contains("@")) { LinphoneContact contact = ContactsManager.getInstance().findContactFromPhoneNumber(to); if (contact != null) { String alias = contact.getContactFromPresenceModelForUriOrTel(to); if (alias != null) { to = alias; } } } LinphonePreferences preferences = LinphonePreferences.instance(); Core core = LinphoneManager.getCore(); Address address; address = core.interpretUrl(to); // InterpretUrl does normalizePhoneNumber if (address == null) { Log.e("[Call Manager] Couldn't convert to String to Address : " + to); return; } ProxyConfig lpc = core.getDefaultProxyConfig(); if (mContext.getResources().getBoolean(R.bool.forbid_self_call) && lpc != null && address.weakEqual(lpc.getIdentityAddress())) { return; } address.setDisplayName(displayName); boolean isLowBandwidthConnection = !LinphoneUtils.isHighBandwidthConnection( LinphoneContext.instance().getApplicationContext()); if (core.isNetworkReachable()) { if (Version.isVideoCapable()) { boolean prefVideoEnable = preferences.isVideoEnabled(); boolean prefInitiateWithVideo = preferences.shouldInitiateVideoCall(); inviteAddress( address, prefVideoEnable && prefInitiateWithVideo, isLowBandwidthConnection); } else { inviteAddress(address, false, isLowBandwidthConnection); } } else { Toast.makeText( mContext, mContext.getString(R.string.error_network_unreachable), Toast.LENGTH_LONG) .show(); Log.e( "[Call Manager] Error: " + mContext.getString(R.string.error_network_unreachable)); } } public void playDtmf(ContentResolver r, char dtmf) { try { if (Settings.System.getInt(r, Settings.System.DTMF_TONE_WHEN_DIALING) == 0) { // audible touch disabled: don't play on speaker, only send in outgoing stream return; } } catch (Settings.SettingNotFoundException e) { Log.e("[Call Manager] playDtmf exception: " + e); } LinphoneManager.getCore().playDtmf(dtmf, -1); } public boolean shouldShowAcceptCallUpdateDialog(Call call) { if (call == null) return true; boolean remoteVideo = call.getRemoteParams().videoEnabled(); boolean localVideo = call.getCurrentParams().videoEnabled(); boolean autoAcceptCameraPolicy = LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests(); return remoteVideo && !localVideo && !autoAcceptCameraPolicy && !call.getCore().isInConference(); } public void setCallInterface(CallActivityInterface callInterface) { mCallInterface = callInterface; } public void resetCallControlsHidingTimer() { if (mCallInterface != null) { mCallInterface.resetCallControlsHidingTimer(); } } public void refreshInCallActions() { if (mCallInterface != null) { mCallInterface.refreshInCallActions(); } } public void removeCallFromConference(Call call) { if (call == null || call.getConference() == null) { return; } call.getConference().removeParticipant(call.getRemoteAddress()); if (call.getCore().getConferenceSize() <= 1) { call.getCore().leaveConference(); } } public void pauseConference() { Core core = LinphoneManager.getCore(); if (core == null) return; if (core.isInConference()) { Log.i("[Call Manager] Pausing conference"); core.leaveConference(); } else { Log.w("[Call Manager] Core isn't in a conference, can't pause it"); } } public void resumeConference() { Core core = LinphoneManager.getCore(); if (core == null) return; if (!core.isInConference()) { Log.i("[Call Manager] Resuming conference"); core.enterConference(); } else { Log.w("[Call Manager] Core is already in a conference, can't resume it"); } } private void inviteAddress( Address address, boolean videoEnabled, boolean lowBandwidth, boolean forceZRTP) { Core core = LinphoneManager.getCore(); CallParams params = core.createCallParams(null); mBandwidthManager.updateWithProfileSettings(params); if (videoEnabled && params.videoEnabled()) { params.enableVideo(true); } else { params.enableVideo(false); } if (lowBandwidth) { params.enableLowBandwidth(true); Log.d("[Call Manager] Low bandwidth enabled in call params"); } if (forceZRTP) { params.setMediaEncryption(MediaEncryption.ZRTP); } String recordFile = FileUtils.getCallRecordingFilename( LinphoneContext.instance().getApplicationContext(), address); params.setRecordFile(recordFile); core.inviteAddressWithParams(address, params); } private boolean reinviteWithVideo() { Core core = LinphoneManager.getCore(); Call call = core.getCurrentCall(); if (call == null) { Log.e("[Call Manager] Trying to add video while not in call"); return false; } if (call.getRemoteParams().lowBandwidthEnabled()) { Log.e("[Call Manager] Remote has low bandwidth, won't be able to do video"); return false; } CallParams params = core.createCallParams(call); if (params.videoEnabled()) return false; // Check if video possible regarding bandwidth limitations mBandwidthManager.updateWithProfileSettings(params); // Abort if not enough bandwidth... if (!params.videoEnabled()) { return false; } // Not yet in video call: try to re-invite with video call.update(params); return true; } private void enableCamera(Call call, boolean enable) { if (call != null) { call.enableCamera(enable); if (mContext.getResources().getBoolean(R.bool.enable_call_notification)) LinphoneContext.instance() .getNotificationManager() .displayCallNotification(LinphoneManager.getCore().getCurrentCall()); } } }