首页 > 编程语言 >linphone-LinphoneManager.java文件分析

linphone-LinphoneManager.java文件分析

时间:2023-05-29 16:07:44浏览次数:46  
标签:mLc null java void return LinphoneManager import linphone public


介绍

本篇主要是对个人对LinphoneManger类的理解及对上面的注释,这是对linphone研究的一个开始. 会慢慢对linphone逐步分析, 随着时间的推进, 我会对linphone有进一步的了解,希望希望了解的同学能跟上我的脚步.

简介

LinphoneManager类是Linphone的主要操作管理类.

主要功能:

官方

/**
 *
 * Manager of the low level LibLinphone stuff.<br />
 * Including:<ul>
 * <li>Starting C liblinphone</li>
 * <li>Reacting to C liblinphone state changes</li>
 * <li>Calling Linphone android service listener methods</li>
 * <li>Interacting from Android GUI/service with low level SIP stuff/</li>
 * </ul>
 *
 * Add Service Listener to react to Linphone state changes.
 *
 * @author Guillaume Beraudo
 *
 */

大致意思是:

  1. 管理linphone核心类的操作文件
  2. 加载c文件的类库
  3. 进行c库的状态交互
  4. 回调linphone方法
  5. 与界面和后台服务进行交互

个人理解
1. 通过LinphoneFactory进行c库文件的加载.
2. 对基础文件进行加载及使用.
3. 对于聊天信息,及传输文件信息类的管理类的操作
4. 对于接打电话及视频的操作.
5. 判断linphone的在线状态.但是好像并不是很完全.
6. 显示接打电话的名称.
7. 设置及判断信道, video编码格式,audio编码格式等.
8. 开启Tunnel的服务类(好像是, 并不太清楚)
9. 对于linphone服务的保活类.
10. 将package中 的文件存储到assets文件夹中.
11. 更新并判断网络状态
12. 对于dmtf的管理
13. 设置接听电话的
14. 音量的配置
15.

/*
  LinphoneManager.java
  Copyright (C) 2010  Belledonne Communications, Grenoble, France

  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package org.linphone;

import static android.media.AudioManager.MODE_RINGTONE;
import static android.media.AudioManager.STREAM_RING;
import static android.media.AudioManager.STREAM_VOICE_CALL;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import org.linphone.compatibility.Compatibility;
import org.linphone.core.CallDirection;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneBuffer;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCallParams;
import org.linphone.core.LinphoneCallStats;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneContent;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.LogCollectionUploadState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneEvent;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneFriendList;
import org.linphone.core.LinphoneInfoMessage;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.PayloadType;
import org.linphone.core.PresenceActivityType;
import org.linphone.core.PresenceModel;
import org.linphone.core.PublishState;
import org.linphone.core.SubscriptionState;
import org.linphone.core.TunnelConfig;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera;
import org.linphone.mediastream.video.capture.hwconf.Hacks;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.telephony.TelephonyManager;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

/**
 *
 * Manager of the low level LibLinphone stuff.<br />
 * Including:<ul>
 * <li>Starting C liblinphone</li>
 * <li>Reacting to C liblinphone state changes</li>
 * <li>Calling Linphone android service listener methods</li>
 * <li>Interacting from Android GUI/service with low level SIP stuff/</li>
 * </ul>
 *
 * Add Service Listener to react to Linphone state changes.
 *
 * @author Guillaume Beraudo
 *
 */
public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessage.LinphoneChatMessageListener {

    private static LinphoneManager instance;
    private Context mServiceContext;
    private AudioManager mAudioManager;
    private PowerManager mPowerManager;
    private Resources mR;
    private LinphonePreferences mPrefs; //存储轻量级数据的类
    private LinphoneCore mLc; // linphone的关键核心接口类,其实现了跟底层接触
    private String lastLcStatusMessage;
    private String basePath;
    private static boolean sExited;
    private boolean mAudioFocused;
    private int mLastNetworkType=-1;
    private ConnectivityManager mConnectivityManager;
    private Handler mHandler = new Handler();
    private WakeLock mIncallWakeLock;
    private static List<LinphoneChatMessage> mPendingChatFileMessage; // 存放所有的聊天类信息
    private static LinphoneChatMessage mUploadPendingFileMessage; // 当个的聊天类信息, 包括文件传输等。

    public String wizardLoginViewDomain = null;
    /** 聊天的回调接口链表 */
    private static List<LinphoneChatMessage.LinphoneChatMessageListener> simpleListeners = new ArrayList<LinphoneChatMessage.LinphoneChatMessageListener>();
    /** 添加和删除listener接口*/
    public static void addListener(LinphoneChatMessage.LinphoneChatMessageListener listener) {
    if (!simpleListeners.contains(listener)) {
        simpleListeners.add(listener);
    }
    }
    public static void removeListener(LinphoneChatMessage.LinphoneChatMessageListener listener) {
    simpleListeners.remove(listener);
    }

    /** 初始化各种存储文件和各种传感器的设备, 就是初始化各种要用到的东西*/
    protected LinphoneManager(final Context c) {
    sExited = false;
    mServiceContext = c;
    basePath = c.getFilesDir().getAbsolutePath();
    mLPConfigXsd = basePath + "/lpconfig.xsd";
    mLinphoneFactoryConfigFile = basePath + "/linphonerc";
    mLinphoneConfigFile = basePath + "/.linphonerc";
    mLinphoneRootCaFile = basePath + "/rootca.pem";
    mRingSoundFile = basePath + "/oldphone_mono.wav";
    mRingbackSoundFile = basePath + "/ringback.wav";
    mPauseSoundFile = basePath + "/hold.mkv";
    mChatDatabaseFile = basePath + "/linphone-history.db";
    mCallLogDatabaseFile = basePath + "/linphone-log-history.db";
    mErrorToneFile = basePath + "/error.wav";
    mConfigFile = basePath + "/configrc";
    mUserCertificatePath = basePath;

    mPrefs = LinphonePreferences.instance();
    mAudioManager = ((AudioManager) c.getSystemService(Context.AUDIO_SERVICE)); // 初始化音频管理器
    mVibrator = (Vibrator) c.getSystemService(Context.VIBRATOR_SERVICE); // 初始化震动管理器
    mPowerManager = (PowerManager) c.getSystemService(Context.POWER_SERVICE); //初始化电源管理器
    mConnectivityManager = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); // 初始化网络连接管理器
    mR = c.getResources();
    mPendingChatFileMessage = new ArrayList<LinphoneChatMessage>();
    }

    private static final int LINPHONE_VOLUME_STREAM = STREAM_VOICE_CALL;
    private static final int dbStep = 4;
    /** Called when the activity is first created. */
    private final String mLPConfigXsd;
    private final String mLinphoneFactoryConfigFile;
    private final String mLinphoneRootCaFile;
    public final String mLinphoneConfigFile;
    private final String mRingSoundFile;
    private final String mRingbackSoundFile;
    private final String mPauseSoundFile;
    private final String mChatDatabaseFile;
    private final String mCallLogDatabaseFile;
    private final String mErrorToneFile;
    private final String mConfigFile;
    private final String mUserCertificatePath;
    private ByteArrayInputStream mUploadingImageStream; //用于文件传输的内存缓冲流对象

    private Timer mTimer;

    /** 但屏幕关闭的时候,keep alive,具体不详, 大致理解*/
    private  BroadcastReceiver mKeepAliveReceiver = new KeepAliveReceiver();

    /**  是否允许声音设备使用*/
    private void routeAudioToSpeakerHelper(boolean speakerOn) {
    Log.w("Routing audio to " + (speakerOn ? "speaker" : "earpiece") + ", disabling bluetooth audio route");
    BluetoothManager.getInstance().disableBluetoothSCO();

    mLc.enableSpeaker(speakerOn);
    }

    /** 允许声音设备使用*/
    public void routeAudioToSpeaker() {
    routeAudioToSpeakerHelper(true);
    }
    /**  获取Android设备的一些信息*/
    public String getUserAgent() throws NameNotFoundException {
    StringBuilder userAgent = new StringBuilder();
    userAgent.append("LinphoneAndroid/" + mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(),0).versionCode);
    userAgent.append(" (");
    userAgent.append("Linphone/" + LinphoneManager.getLc().getVersion() + "; ");
    userAgent.append(Build.DEVICE + " " + Build.MODEL +  " Android/" + Build.VERSION.SDK_INT);
    userAgent.append(")");
    return userAgent.toString();
    }

    /** 允许声音设备 */
    public void routeAudioToReceiver() {
    routeAudioToSpeakerHelper(false);
    }

    /** 创建并开启LibLinphone, 就是创建一个实例对象*/
    public synchronized static final LinphoneManager createAndStart(Context c) {
    if (instance != null)
        throw new RuntimeException("Linphone Manager is already initialized");

    instance = new LinphoneManager(c);
    instance.startLibLinphone(c);
    /**  Provides access to information about the telephony services on the device.*/
    TelephonyManager tm = (TelephonyManager) c.getSystemService(Context.TELEPHONY_SERVICE);
    /** CALL_STATE_IDLE:Device call state:No activity*/
    boolean gsmIdle = tm.getCallState() == TelephonyManager.CALL_STATE_IDLE;
    setGsmIdle(gsmIdle);
    return instance;
    }

    /**  添加一个聊天信息*/
    public void addDownloadMessagePending(LinphoneChatMessage message){
    synchronized (mPendingChatFileMessage) {
        mPendingChatFileMessage.add(message);
    }
    }

    /**  判断这个消息是否已经添加到消息列表中了*/
    public boolean isMessagePending(LinphoneChatMessage message){
    boolean messagePending = false;
    synchronized (mPendingChatFileMessage) {
        for (LinphoneChatMessage chat : mPendingChatFileMessage) {
        if (chat.getStorageId() == message.getStorageId()) {
            messagePending = true;
            break;
        }
        }
    }
    return messagePending;
    }

    /**  这个聊天对话体删除*/
    public void removePendingMessage(LinphoneChatMessage message){
    synchronized (mPendingChatFileMessage) {
        for (LinphoneChatMessage chat : mPendingChatFileMessage) {
        if (chat.getStorageId() == message.getStorageId()) {
            mPendingChatFileMessage.remove(chat);
        }
        break;
        }
    }
    }

    /**  用于文件传输的聊天对话类对象*/
    public void setUploadPendingFileMessage(LinphoneChatMessage message){
    mUploadPendingFileMessage = message;
    }
    /**  获取这个用于文件传输的消息体*/
    public LinphoneChatMessage getMessageUploadPending(){
    return mUploadPendingFileMessage;
    }

    /** 设置内存流的数据 */
    public void setUploadingImageStream(ByteArrayInputStream array){
    this.mUploadingImageStream = array;
    }

    @Override
    public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, LinphoneChatMessage.State state) {
    if (state == LinphoneChatMessage.State.FileTransferDone) {  // 数据传送完毕
        if(msg.isOutgoing() && mUploadingImageStream != null){
        mUploadPendingFileMessage = null;
        mUploadingImageStream = null;
        } else {
        File file = new File(Environment.getExternalStorageDirectory(), msg.getAppData());
        try {
            String url = MediaStore.Images.Media.insertImage(getContext().getContentResolver(), file.getPath(), file.getName(), null);
            msg.setAppData(url);
            file.delete();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        removePendingMessage(msg);
        }
    }

    if(state == LinphoneChatMessage.State.FileTransferError) {
        //TODO
    }

    for (LinphoneChatMessage.LinphoneChatMessageListener l: simpleListeners) {
        l.onLinphoneChatMessageStateChanged(msg, state);
    }
    }

    @Override
    public void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer) {
    }

    /**  发送数据*/
    @Override
    public void onLinphoneChatMessageFileTransferSent(LinphoneChatMessage msg, LinphoneContent content, int offset, int size, LinphoneBuffer bufferToFill) {
    if (mUploadingImageStream != null && size > 0) {
        byte[] data = new byte[size];
        int read = mUploadingImageStream.read(data, 0, size);
        if (read > 0) {
        bufferToFill.setContent(data);
        bufferToFill.setSize(read);
        } else {
        Log.e("Error, upload task asking for more bytes(" + size + ") than available (" + mUploadingImageStream.available() + ")");
        }
    }
    }

    /**  通知每一个回调,文件传输发生的变化*/
    @Override
    public void onLinphoneChatMessageFileTransferProgressChanged(LinphoneChatMessage msg, LinphoneContent content, int offset, int total) {
    for (LinphoneChatMessage.LinphoneChatMessageListener l: simpleListeners) {
        l.onLinphoneChatMessageFileTransferProgressChanged(msg, content, offset, total);
    }
    }

    /**  是否存在Model或Acitivty是否存在, 并不是很明确, 不影响分析*/
    private boolean isPresenceModelActivitySet() {
    LinphoneCore lc = getLcIfManagerNotDestroyedOrNull();
    if (isInstanciated() && lc != null) {
        return lc.getPresenceModel() != null && lc.getPresenceModel().getActivity() != null;
    }
    return false;
    }

    /**  设置状态在线, 如果Model不存在, 创建Model并设置*/
    public void changeStatusToOnline() {
    LinphoneCore lc = getLcIfManagerNotDestroyedOrNull();
    if (isInstanciated() && lc != null && isPresenceModelActivitySet() && lc.getPresenceModel().getActivity().getType() != PresenceActivityType.Online) {
        lc.getPresenceModel().getActivity().setType(PresenceActivityType.Online);
    } else if (isInstanciated() && lc != null && !isPresenceModelActivitySet()) {
        PresenceModel model = LinphoneCoreFactory.instance().createPresenceModel(PresenceActivityType.Online, null);
        lc.setPresenceModel(model);
    }
    }

    /** 设置状态为OnThePhone*/
    public void changeStatusToOnThePhone() {
    LinphoneCore lc = getLcIfManagerNotDestroyedOrNull();
    if (isInstanciated() && isPresenceModelActivitySet() && lc.getPresenceModel().getActivity().getType() != PresenceActivityType.OnThePhone) {
        lc.getPresenceModel().getActivity().setType(PresenceActivityType.OnThePhone);
    } else if (isInstanciated() && !isPresenceModelActivitySet()) {
        PresenceModel model = LinphoneCoreFactory.instance().createPresenceModel(PresenceActivityType.OnThePhone, null);
        lc.setPresenceModel(model);
    }
    }

    /**  设置状态为Offline*/
    public void changeStatusToOffline() {
    LinphoneCore lc = getLcIfManagerNotDestroyedOrNull();
    if (isInstanciated() && isPresenceModelActivitySet() && lc.getPresenceModel().getActivity().getType() != PresenceActivityType.Offline) {
        lc.getPresenceModel().getActivity().setType(PresenceActivityType.Offline);
    } else if (isInstanciated() && !isPresenceModelActivitySet()) {
        PresenceModel model = LinphoneCoreFactory.instance().createPresenceModel(PresenceActivityType.Offline, null);
        lc.setPresenceModel(model);
    }
    }

    /**  得到instance对象实例, 问题:为啥上面还有一个create..()函数呢?*/
    public static synchronized final LinphoneManager getInstance() {
    if (instance != null) return instance;

    if (sExited) {
        throw new RuntimeException("Linphone Manager was already destroyed. "
                       + "Better use getLcIfManagerNotDestroyed and check returned value");
    }

    throw new RuntimeException("Linphone Manager should be created before accessed");
    }

    /**  获取到LinphoneCore对象实例,进行对底层的操作*/
    public static synchronized final LinphoneCore getLc() {
    return getInstance().mLc;
    }

    /**  得到lpconfig.xsd的路径*/
    public String getLPConfigXsdPath() {
    return mLPConfigXsd;
    }
    /**  来了一个新的电话,往外打出的电话*/
    public void newOutgoingCall(AddressType address) {
    String to = address.getText().toString();
    newOutgoingCall(to, address.getDisplayedName());
    }

    public void newOutgoingCall(String to, String displayName) {
    //      if (mLc.isIncall()) {
    //          listenerDispatcher.tryingNewOutgoingCallButAlreadyInCall();
    //          return;
    //      }
    LinphoneAddress lAddress;
    try {
        lAddress = mLc.interpretUrl(to); // 得到LinphoneAddress类型的地址
        LinphoneProxyConfig lpc = mLc.getDefaultProxyConfig();
        // 判断某个条件,不满足此次拨打电话无效. 1. 限制本机打电话(应该是) 2. 从底层判断是否符合Uri的条件
        if (mR.getBoolean(R.bool.forbid_self_call) && lpc!=null && lAddress.asStringUriOnly().equals(lpc.getIdentity())) {
        return;
        }
    } catch (LinphoneCoreException e) {
        return;
    }
    lAddress.setDisplayName(displayName);

    boolean isLowBandwidthConnection = !LinphoneUtils.isHighBandwidthConnection(LinphoneService.instance().getApplicationContext());

    /** 网络是否可以到达*/
    if (mLc.isNetworkReachable()) {
        try {
        if (Version.isVideoCapable()) {
            boolean prefVideoEnable = mPrefs.isVideoEnabled();
            boolean prefInitiateWithVideo = mPrefs.shouldInitiateVideoCall();
            CallManager.getInstance().inviteAddress(lAddress, prefVideoEnable && prefInitiateWithVideo, isLowBandwidthConnection);
        } else {
            CallManager.getInstance().inviteAddress(lAddress, false, isLowBandwidthConnection);
        }


        } catch (LinphoneCoreException e) {
        return;
        }
    } else if (LinphoneActivity.isInstanciated()) {
        LinphoneActivity.instance().displayCustomToast(getString(R.string.error_network_unreachable), Toast.LENGTH_LONG);
    } else {
        Log.e("Error: " + getString(R.string.error_network_unreachable));
    }
    }

    /** 初始化摄像头的参数 */
    private void resetCameraFromPreferences() {
    boolean useFrontCam = mPrefs.useFrontCam();

    int camId = 0;
    AndroidCamera[] cameras = AndroidCameraConfiguration.retrieveCameras();
    for (AndroidCamera androidCamera : cameras) {
        if (androidCamera.frontFacing == useFrontCam)
        camId = androidCamera.id;
    }
    /**  将摄像头的id传给底层*/
    LinphoneManager.getLc().setVideoDevice(camId);
    }

    public static interface AddressType {
    void setText(CharSequence s);
    CharSequence getText();
    void setDisplayedName(String s);
    String getDisplayedName();
    }


    public static interface NewOutgoingCallUiListener {
    public void onWrongDestinationAddress();
    public void onCannotGetCallParameters();
    public void onAlreadyInCall();
    }

    /**  是否使用Camera, toggle是开关的意思*/
    public boolean toggleEnableCamera() {
    if (mLc.isIncall()) {
        boolean enabled = !mLc.getCurrentCall().cameraEnabled();
        enableCamera(mLc.getCurrentCall(), enabled);
        return enabled;
    }
    return false;
    }

    /** 是否允许Camera显示,并判断是否显示Notification*/
    public void enableCamera(LinphoneCall call, boolean enable) {
    if (call != null) {
        call.enableCamera(enable);
        if (mServiceContext.getResources().getBoolean(R.bool.enable_call_notification))
        LinphoneService.instance().refreshIncallIcon(mLc.getCurrentCall());
    }
    }

    /**  */
    public void sendStaticImage(boolean send) {
    if (mLc.isIncall()) {
        enableCamera(mLc.getCurrentCall(), !send);
    }
    }

    /**palyDtmf 也不知道是啥玩意儿, DTMF:双音多频信号(DTMF)*/
    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 (SettingNotFoundException e) {}

    getLc().playDtmf(dtmf, -1);
    }

    /**  终止电话*/
    public void terminateCall() {
    if (mLc.isIncall()) {
        mLc.terminateCall(mLc.getCurrentCall());
    }
    }

    /** 初始化Tunnel, 具体估计也就是接受*/
    public void initTunnelFromConf() {
    if (!mLc.isTunnelAvailable())
        return;

    NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
    mLc.tunnelCleanServers();
    TunnelConfig config = mPrefs.getTunnelConfig();
    if (config.getHost() != null) {
        mLc.tunnelAddServer(config);
        manageTunnelServer(info);
    }
    }

    /** WIFI或3G某一特定模式可以设置为true */
    private boolean isTunnelNeeded(NetworkInfo info) {
    if (info == null) {
        Log.i("No connectivity: tunnel should be disabled");
        return false;
    }

    String pref = mPrefs.getTunnelMode();

    if (getString(R.string.tunnel_mode_entry_value_always).equals(pref)) {
        return true;
    }

    if (info.getType() != ConnectivityManager.TYPE_WIFI
        && getString(R.string.tunnel_mode_entry_value_3G_only).equals(pref)) {
        Log.i("need tunnel: 'no wifi' connection");
        return true;
    }

    return false;
    }

    /** 管理Tunnel */
    private void manageTunnelServer(NetworkInfo info) {
    if (mLc == null) return;
    if (!mLc.isTunnelAvailable()) return;

    Log.i("Managing tunnel");
    if (isTunnelNeeded(info)) {
        Log.i("Tunnel need to be activated");
        mLc.tunnelSetMode(LinphoneCore.TunnelMode.enable);
    } else {
        Log.i("Tunnel should not be used");
        String pref = mPrefs.getTunnelMode();
        mLc.tunnelSetMode(LinphoneCore.TunnelMode.disable);
        if (getString(R.string.tunnel_mode_entry_value_auto).equals(pref)) {
        mLc.tunnelSetMode(LinphoneCore.TunnelMode.auto);
        }
    }
    }

    /** 取消保活Linphone*/
    public synchronized final void destroyLinphoneCore() {
    sExited = true;
    BluetoothManager.getInstance().destroy();
    try {
        mTimer.cancel();
        mLc.destroy();
    }
    catch (RuntimeException e) {
        e.printStackTrace();
    }
    finally {
        mServiceContext.unregisterReceiver(instance.mKeepAliveReceiver);
        mLc = null;
    }
    }

    /** 重新启动Linphone */
    public void restartLinphoneCore(){
    destroyLinphoneCore();
    startLibLinphone(mServiceContext);
    sExited = false;
    }

    /** 创建LinphoneCoreFactoryImple, 在这个类里加载了so库 */
    private synchronized void startLibLinphone(Context c) {
    try {
        copyAssetsFromPackage();
        //traces alway start with traces enable to not missed first initialization
        boolean isDebugLogEnabled = !(mR.getBoolean(R.bool.disable_every_log));
        LinphoneCoreFactory.instance().setDebugMode(isDebugLogEnabled, getString(R.string.app_name));
        LinphoneCoreFactory.instance().enableLogCollection(isDebugLogEnabled);

        mLc = LinphoneCoreFactory.instance().createLinphoneCore(this, mLinphoneConfigFile, mLinphoneFactoryConfigFile, null, c);


        TimerTask lTask = new TimerTask() {
            @Override
            public void run() {
            UIThreadDispatcher.dispatch(new Runnable() {
                @Override
                public void run() {
                    if (mLc != null) {
                    mLc.iterate();
                    }
                }
                });
            }
        };
        /*use schedule instead of scheduleAtFixedRate to avoid iterate from being call in burst after cpu wake up*/
        mTimer = new Timer("Linphone scheduler");
        mTimer.schedule(lTask, 0, 20);
    }
    catch (Exception e) {
        e.printStackTrace();
        Log.e(e, "Cannot start linphone");
    }
    }

    // 初始化linphone, 完全是关于初始化linphone的参数, 例如Camera, 网络,等
    private synchronized void initLiblinphone(LinphoneCore lc) throws LinphoneCoreException {
    mLc = lc;
    boolean isDebugLogEnabled = !(mR.getBoolean(R.bool.disable_every_log)) && mPrefs.isDebugEnabled();
    LinphoneCoreFactory.instance().setDebugMode(isDebugLogEnabled, getString(R.string.app_name));
    LinphoneCoreFactory.instance().enableLogCollection(isDebugLogEnabled);

    // 关于linphone的配置文件。
    PreferencesMigrator prefMigrator = new PreferencesMigrator(mServiceContext);
    prefMigrator.migrateRemoteProvisioningUriIfNeeded();
    prefMigrator.migrateSharingServerUrlIfNeeded();

    if (prefMigrator.isMigrationNeeded()) {
        prefMigrator.doMigration();
    }

    // Some devices could be using software AEC before
    // This will disable it in favor of hardware AEC if available
    if (prefMigrator.isEchoMigratioNeeded()) {
        Log.d("Echo canceller configuration need to be updated");
        prefMigrator.doEchoMigration();
        mPrefs.echoConfigurationUpdated();
    }

    mLc.setContext(mServiceContext);
    mLc.setZrtpSecretsCache(basePath + "/zrtp_secrets");

    try {
        String versionName = mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(), 0).versionName;
        if (versionName == null) {
        versionName = String.valueOf(mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(), 0).versionCode);
        }
        mLc.setUserAgent("LinphoneAndroid", versionName);
    } catch (NameNotFoundException e) {
        Log.e(e, "cannot get version name");
    }
    mLc.setRing(mRingSoundFile);
    if (mR.getBoolean(R.bool.use_linphonecore_ringing)) {
        disableRinging();
    } else {
        mLc.setRing(null); //We'll use the android media player api to play the ringtone
    }
    mLc.setRingback(mRingbackSoundFile);  // 声音
    mLc.setRootCA(mLinphoneRootCaFile);   //
    mLc.setPlayFile(mPauseSoundFile);     //
    mLc.setChatDatabasePath(mChatDatabaseFile);
    mLc.setCallLogsDatabasePath(mCallLogDatabaseFile);
    mLc.setUserCertificatesPath(mUserCertificatePath);
    //mLc.setCallErrorTone(Reason.NotFound, mErrorToneFile);

    int availableCores = Runtime.getRuntime().availableProcessors();
    Log.w("MediaStreamer : " + availableCores + " cores detected and configured");
    mLc.setCpuCount(availableCores);  // 设置有效的cpu数量

    int migrationResult = getLc().migrateToMultiTransport();
    Log.d("Migration to multi transport result = " + migrationResult);

    mLc.migrateCallLogs();

    if (mServiceContext.getResources().getBoolean(R.bool.enable_push_id)) {
        Compatibility.initPushNotificationService(mServiceContext);
    }

    IntentFilter lFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        lFilter.addAction(Intent.ACTION_SCREEN_OFF);
        mServiceContext.registerReceiver(mKeepAliveReceiver, lFilter);  // 注册保存

    updateNetworkReachability();  // 更新网络连接的状态

    if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
        BluetoothManager.getInstance().initBluetooth();  // 竟然使用了蓝牙管理, 后期看看有什么作用
    }

    resetCameraFromPreferences();  // 初始化Camera参数
    mLc.setFileTransferServer(LinphonePreferences.instance().getSharingPictureServerUrl()); //这个是跟传输文件有关
    }

    // 将Assets文件复制出来从pakcaage中, 从哪里不用太大关心
    private void copyAssetsFromPackage() throws IOException {
    copyIfNotExist(R.raw.oldphone_mono, mRingSoundFile);
    copyIfNotExist(R.raw.ringback, mRingbackSoundFile);
    copyIfNotExist(R.raw.hold, mPauseSoundFile);
    copyIfNotExist(R.raw.incoming_chat, mErrorToneFile);
    copyIfNotExist(R.raw.linphonerc_default, mLinphoneConfigFile);
    copyFromPackage(R.raw.linphonerc_factory, new File(mLinphoneFactoryConfigFile).getName());
    copyIfNotExist(R.raw.lpconfig, mLPConfigXsd);
    copyIfNotExist(R.raw.rootca, mLinphoneRootCaFile);
    }

    // 如果存在久复制出来
    public void copyIfNotExist(int ressourceId, String target) throws IOException {
    File lFileToCopy = new File(target);
    if (!lFileToCopy.exists()) {
        copyFromPackage(ressourceId,lFileToCopy.getName());
    }
    }

    // 将数据文件通过流弄出来
    public void copyFromPackage(int ressourceId, String target) throws IOException{
    FileOutputStream lOutputStream = mServiceContext.openFileOutput (target, 0);
    InputStream lInputStream = mR.openRawResource(ressourceId);
    int readByte;
    byte[] buff = new byte[8048];
    while (( readByte = lInputStream.read(buff)) != -1) {
        lOutputStream.write(buff,0, readByte);
    }
    lOutputStream.flush();
    lOutputStream.close();
    lInputStream.close();
    }

    //public void loadConfig(){
    //  try {
    //      copyIfNotExist(R.raw.configrc, mConfigFile);
    //  } catch (Exception e){
    //      Log.w(e);
    //  }
    //  LinphonePreferences.instance().setRemoteProvisioningUrl("file://" + mConfigFile);
    //  getLc().getConfig().setInt("misc","transient_provisioning",1);
    //}

    //检查是否符合Video格式
    public boolean detectVideoCodec(String mime) {
    for (PayloadType videoCodec : mLc.getVideoCodecs()) {
        if (mime.equals(videoCodec.getMime())) return true;
    }
    return false;
    }

    // 检查是否符合Audio的编码格式
    public boolean detectAudioCodec(String mime){
    for (PayloadType audioCodec : mLc.getAudioCodecs()) {
        if (mime.equals(audioCodec.getMime())) return true;
    }
    return false;
    }

    //  更新网络连接的状态
    public void updateNetworkReachability() {
    ConnectivityManager cm = (ConnectivityManager) mServiceContext.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo eventInfo = cm.getActiveNetworkInfo();

    if (eventInfo == null || eventInfo.getState() == NetworkInfo.State.DISCONNECTED) {
        Log.i("No connectivity: setting network unreachable");
        mLc.setNetworkReachable(false);
    } else if (eventInfo.getState() == NetworkInfo.State.CONNECTED){
        manageTunnelServer(eventInfo);

        boolean wifiOnly = LinphonePreferences.instance().isWifiOnlyEnabled();
        if (wifiOnly){
        if (eventInfo.getType()==ConnectivityManager.TYPE_WIFI)
            mLc.setNetworkReachable(true);
        else {
            Log.i("Wifi-only mode, setting network not reachable");
            mLc.setNetworkReachable(false);
        }
        }else{
        int curtype=eventInfo.getType();

        if (curtype!=mLastNetworkType){
            //if kind of network has changed, we need to notify network_reachable(false) to make sure all current connections are destroyed.
            //they will be re-created during setNetworkReachable(true).
            Log.i("Connectivity has changed.");
            mLc.setNetworkReachable(false);
        }
        mLc.setNetworkReachable(true);
        mLastNetworkType=curtype;
        }
    }
    }

    // 结束保活广播和销毁BluetoothManager实例等,以及停止倒计时
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void doDestroy() {
    if (LinphoneService.isReady()) // indeed, no need to crash
        ChatStorage.getInstance().close();

    BluetoothManager.getInstance().destroy();
    try {
        mTimer.cancel();
        mLc.destroy();
    }
    catch (RuntimeException e) {
        e.printStackTrace();
    }
    finally {
        mServiceContext.unregisterReceiver(instance.mKeepAliveReceiver);
        mLc = null;
        instance = null;
    }
    }

    // 将linphone设置为offline
    public static synchronized void destroy() {
    if (instance == null) return;
    getInstance().changeStatusToOffline();
    sExited = true;
    instance.doDestroy();
    }

    // 根据key值,获取数据
    private String getString(int key) {
    return mR.getString(key);
    }

    /* Simple implementation as Android way seems very complicate:
       For example: with wifi and mobile actives; when pulling mobile down:
       I/Linphone( 8397): WIFI connected: setting network reachable
       I/Linphone( 8397): new state [RegistrationProgress]
       I/Linphone( 8397): mobile disconnected: setting network unreachable
       I/Linphone( 8397): Managing tunnel
       I/Linphone( 8397): WIFI connected: setting network reachable
    */
    public void connectivityChanged(ConnectivityManager cm, boolean noConnectivity) {
    updateNetworkReachability();
    }

    //
    public interface EcCalibrationListener {
    void onEcCalibrationStatus(EcCalibratorStatus status, int delayMs);
    }

    // 代表了一个电话
    private LinphoneCall ringingCall;

    private MediaPlayer mRingerPlayer; // 音量播放
    private Vibrator mVibrator;        // 震动

    public void displayWarning(LinphoneCore lc, String message) {}  // 播放警告操作

    public void authInfoRequested(LinphoneCore lc, String realm, String username, String domain) {}
    public void byeReceived(LinphoneCore lc, String from) {}
    public void displayMessage(LinphoneCore lc, String message) {}
    public void show(LinphoneCore lc) {}

    public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url) {
    }

    public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {
    }

    @Override
    public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {
    Log.d("DTMF received: " + dtmf);
    }

    //接收消息处理消息的类
    @Override
    public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {
    if (mServiceContext.getResources().getBoolean(R.bool.disable_chat)) {
        return;
    }

    LinphoneAddress from = message.getFrom();

    String textMessage = message.getText();
    String url = message.getExternalBodyUrl();
    if (textMessage != null && textMessage.length() > 0) {
        ChatStorage.getInstance().saveTextMessage(from.asStringUriOnly(), "", textMessage, message.getTime());
    } else if (url != null && url.length() > 0) {
        ChatStorage.getInstance().saveImageMessage(from.asStringUriOnly(), "", null, message.getExternalBodyUrl(), message.getTime());
    }

    try {
        Contact contact = ContactsManager.getInstance().findContactWithAddress(mServiceContext.getContentResolver(), from);
        if (!mServiceContext.getResources().getBoolean(R.bool.disable_chat_message_notification)) {
        if (LinphoneActivity.isInstanciated() && !LinphoneActivity.instance().displayChatMessageNotification(from.asStringUriOnly())) {
            return;
        } else {
            if (contact != null) {
            LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), contact.getName(), textMessage);
            } else {
            LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), from.getUserName(), textMessage);
            }
        }
        }
    } catch (Exception e) {
        Log.e(e);
    }
    }

    // 获取最后一个状态消息
    public String getLastLcStatusMessage() {
    return lastLcStatusMessage;
    }

    // 显示状态消息
    public void displayStatus(final LinphoneCore lc, final String message) {
    Log.i(message);
    lastLcStatusMessage=message;
    }

    // 判断全局的状态, 如果为GlobalOn则开启linphone的初始化配置.
    public void globalState(final LinphoneCore lc, final GlobalState state, final String message) {
    Log.i("New global state [",state,"]");
    if (state == GlobalState.GlobalOn){
        try {
        initLiblinphone(lc);
        } catch (LinphoneCoreException e) {
        Log.e(e);
        }
    }
    }


    public void registrationState(final LinphoneCore lc, final LinphoneProxyConfig proxy,final RegistrationState state,final String message) {
    Log.i("New registration state ["+state+"]");
    }

    private int savedMaxCallWhileGsmIncall;
    /**  保存SIP电话接收的状态*/
    private synchronized void preventSIPCalls() {
    if (savedMaxCallWhileGsmIncall != 0) {
        Log.w("SIP calls are already blocked due to GSM call running");
        return;
    }
    savedMaxCallWhileGsmIncall = mLc.getMaxCalls();
    mLc.setMaxCalls(0);
    }
    /** 接收SIP拨来的电话*/
    private synchronized void allowSIPCalls() {
    if (savedMaxCallWhileGsmIncall == 0) {
        Log.w("SIP calls are already allowed as no GSM call known to be running");
        return;
    }
    mLc.setMaxCalls(savedMaxCallWhileGsmIncall);
    savedMaxCallWhileGsmIncall = 0;
    }
    /** 判断电话接收的状态,如果有点话,不执行SIP操作,如果没有执行SIP操作*/
    public static void setGsmIdle(boolean gsmIdle) {
    LinphoneManager mThis = instance;
    if (mThis == null) return;
    if (gsmIdle) {
        mThis.allowSIPCalls();
    } else {
        mThis.preventSIPCalls();
    }
    }

    public Context getContext() {
    try {
        if (LinphoneActivity.isInstanciated())
        return LinphoneActivity.instance();
        else if (CallActivity.isInstanciated())
        return CallActivity.instance();
        else if (CallIncomingActivity.isInstanciated())
        return CallIncomingActivity.instance();
        else if (mServiceContext != null)
        return mServiceContext;
        else if (LinphoneService.isReady())
        return LinphoneService.instance().getApplicationContext();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
    }
    // 根据不同的状态,进行相应的操作, 比如接听电话,停止响铃,
    @SuppressLint("Wakelock")
    public void callState(final LinphoneCore lc,final LinphoneCall call, final State state, final String message) {
    Log.i("New call state [",state,"]");
    if (state == State.IncomingReceived && !call.equals(lc.getCurrentCall())) {
        if (call.getReplacedCall()!=null){
        // attended transfer
        // it will be accepted automatically.
        return;
        }
    }

    if (state == State.IncomingReceived && mR.getBoolean(R.bool.auto_answer_calls)) {
        try {
        mLc.acceptCall(call);
        } catch (LinphoneCoreException e) {
        e.printStackTrace();
        }
    }
    else if (state == State.IncomingReceived || (state == State.CallIncomingEarlyMedia && mR.getBoolean(R.bool.allow_ringing_while_early_media))) {
        // Brighten screen for at least 10 seconds
        if (mLc.getCallsNb() == 1) {
        BluetoothManager.getInstance().disableBluetoothSCO(); // Just in case

        ringingCall = call;
        startRinging();
        // otherwise there is the beep
        }
    } else if (call == ringingCall && isRinging) {
        //previous state was ringing, so stop ringing
        stopRinging();
    }

    if (state == State.Connected) {
        if (mLc.getCallsNb() == 1) {
        requestAudioFocus();
        Compatibility.setAudioManagerInCallMode(mAudioManager);
        }

        if (Hacks.needSoftvolume()) {
        Log.w("Using soft volume audio hack");
        adjustVolume(0); // Synchronize
        }
    }

    if (state == State.OutgoingEarlyMedia) {
        Compatibility.setAudioManagerInCallMode(mAudioManager);
    }

    if (state == State.CallReleased || state == State.Error) {
        if (mLc.getCallsNb() == 0) {
        if (mAudioFocused){
            int res = mAudioManager.abandonAudioFocus(null);
            Log.d("Audio focus released a bit later: " + (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED ? "Granted" : "Denied"));
            mAudioFocused = false;
        }

        Context activity = getContext();
        if (activity != null) {
            TelephonyManager tm = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);
            if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
            Log.d("---AudioManager: back to MODE_NORMAL");
            mAudioManager.setMode(AudioManager.MODE_NORMAL);
            Log.d("All call terminated, routing back to earpiece");
            routeAudioToReceiver();
            }
        }
        }
    }

    if (state == State.CallEnd) {
        if (mLc.getCallsNb() == 0) {
        if (mIncallWakeLock != null && mIncallWakeLock.isHeld()) {
            mIncallWakeLock.release();
            Log.i("Last call ended: releasing incall (CPU only) wake lock");
        } else {
            Log.i("Last call ended: no incall (CPU only) wake lock were held");
        }
        }
    }

    if (state == State.StreamsRunning) {
        if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
        BluetoothManager.getInstance().routeAudioToBluetooth();
        // Hack to ensure the bluetooth route is really used
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                BluetoothManager.getInstance().routeAudioToBluetooth();
            }
            }, 500);
        }

        if (mIncallWakeLock == null) {
        mIncallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "incall");
        }
        if (!mIncallWakeLock.isHeld()) {
        Log.i("New call active : acquiring incall (CPU only) wake lock");
        mIncallWakeLock.acquire();
        } else {
        Log.i("New call active while incall (CPU only) wake lock already active");
        }
    }
    }

    public void callStatsUpdated(final LinphoneCore lc, final LinphoneCall call, final LinphoneCallStats stats) {}

    public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,
                      boolean encrypted, String authenticationToken) {
    }

    public void startEcCalibration(LinphoneCoreListener l) throws LinphoneCoreException {
    routeAudioToSpeaker();
    int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
    int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
    mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0);
    mLc.startEchoCalibration(l);

    mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0);
    }

    private boolean isRinging;
    private boolean disableRinging = false;

    public void disableRinging() {
    disableRinging = true;
    }

    private void requestAudioFocus(){
    if (!mAudioFocused){
        int res = mAudioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT );
        Log.d("Audio focus requested: " + (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED ? "Granted" : "Denied"));
        if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) mAudioFocused=true;
    }
    }

    private synchronized void startRinging()  {
    if (disableRinging) {
        routeAudioToSpeaker();
        return;
    }
    if (mR.getBoolean(R.bool.allow_ringing_while_early_media)) {
        routeAudioToSpeaker(); // Need to be able to ear the ringtone during the early media
    }

    if (Hacks.needGalaxySAudioHack()) {
        mAudioManager.setMode(MODE_RINGTONE);
    }

    try {
        if ((mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) && mVibrator != null) {
        long[] patern = {0,1000,1000};
        mVibrator.vibrate(patern, 1);
        }
        if (mRingerPlayer == null) {
        requestAudioFocus();
        mRingerPlayer = new MediaPlayer();
        mRingerPlayer.setAudioStreamType(STREAM_RING);

        String ringtone = LinphonePreferences.instance().getRingtone(android.provider.Settings.System.DEFAULT_RINGTONE_URI.toString());
        try {
            if (ringtone.startsWith("content://")) {
            mRingerPlayer.setDataSource(mServiceContext, Uri.parse(ringtone));
            } else {
            FileInputStream fis = new FileInputStream(ringtone);
            mRingerPlayer.setDataSource(fis.getFD());
            fis.close();
            }
        } catch (IOException e) {
            Log.e(e, "Cannot set ringtone");
        }

        mRingerPlayer.prepare();
        mRingerPlayer.setLooping(true);
        mRingerPlayer.start();
        } else {
        Log.w("already ringing");
        }
    } catch (Exception e) {
        Log.e(e,"cannot handle incoming call");
    }
    isRinging = true;
    }

    private synchronized void stopRinging() {
    if (mRingerPlayer != null) {
        mRingerPlayer.stop();
        mRingerPlayer.release();
        mRingerPlayer = null;
    }
    if (mVibrator != null) {
        mVibrator.cancel();
    }

    if (Hacks.needGalaxySAudioHack())
        mAudioManager.setMode(AudioManager.MODE_NORMAL);

    isRinging = false;
    // You may need to call galaxys audio hack after this method
    if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
        if (mServiceContext.getResources().getBoolean(R.bool.isTablet)) {
        Log.d("Stopped ringing, routing back to speaker");
        routeAudioToSpeaker();
        } else {
        Log.d("Stopped ringing, routing back to earpiece");
        routeAudioToReceiver();
        }
    }
    }

    // 显示显示来电的名称, 如果没有则是默认的
    public static String extractADisplayName(Resources r, LinphoneAddress address) {
    if (address == null) return r.getString(R.string.unknown_incoming_call_name);

    final String displayName = address.getDisplayName();
    if (displayName!=null) {
        return displayName;
    } else  if (address.getUserName() != null){
        return address.getUserName();
    } else {
        String rms = address.toString();
        if (rms != null && rms.length() > 1)
        return rms;

        return r.getString(R.string.unknown_incoming_call_name);
    }
    }

    // 重新请求视频
    public static boolean reinviteWithVideo() {
    return CallManager.getInstance().reinviteWithVideo();
    }

    /**
     *
     * @return false if already in video call.
     */
    public boolean addVideo() {
    LinphoneCall call = mLc.getCurrentCall();
    enableCamera(call, true);
    return reinviteWithVideo();
    }

    //
    public boolean acceptCallIfIncomingPending() throws LinphoneCoreException {
    if (mLc.isInComingInvitePending()) {
        mLc.acceptCall(mLc.getCurrentCall());
        return true;
    }
    return false;
    }

    public boolean acceptCall(LinphoneCall call) {
    try {
        mLc.acceptCall(call);
        return true;
    } catch (LinphoneCoreException e) {
        Log.i(e, "Accept call failed");
    }
    return false;
    }

    public boolean acceptCallWithParams(LinphoneCall call, LinphoneCallParams params) {
    try {
        mLc.acceptCallWithParams(call, params);
        return true;
    } catch (LinphoneCoreException e) {
        Log.i(e, "Accept call failed");
    }
    return false;
    }

    public static String extractIncomingRemoteName(Resources r, LinphoneAddress linphoneAddress) {
    return extractADisplayName(r, linphoneAddress);
    }

    //配置音量
    public void adjustVolume(int i) {
    if (Build.VERSION.SDK_INT < 15) {
        int oldVolume = mAudioManager.getStreamVolume(LINPHONE_VOLUME_STREAM);
        int maxVolume = mAudioManager.getStreamMaxVolume(LINPHONE_VOLUME_STREAM);

        int nextVolume = oldVolume +i;
        if (nextVolume > maxVolume) nextVolume = maxVolume;
        if (nextVolume < 0) nextVolume = 0;

        mLc.setPlaybackGain((nextVolume - maxVolume)* dbStep);
    } else
        // starting from ICS, volume must be adjusted by the application, at least for STREAM_VOICE_CALL volume stream
        mAudioManager.adjustStreamVolume(LINPHONE_VOLUME_STREAM, i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
    }

    // 附近是否有Sensor(传感器)存在
    public static Boolean isProximitySensorNearby(final SensorEvent event) {
    float threshold = 4.001f; // <= 4 cm is near

    final float distanceInCm = event.values[0];
    final float maxDistance = event.sensor.getMaximumRange();
    Log.d("Proximity sensor report [",distanceInCm,"] , for max range [",maxDistance,"]");

    if (maxDistance <= threshold) {
        // Case binary 0/1 and short sensors
        threshold = maxDistance;
    }

    return distanceInCm < threshold;
    }

    private static boolean sLastProximitySensorValueNearby;
    private static Set<Activity> sProximityDependentActivities = new HashSet<Activity>();
    private static SensorEventListener sProximitySensorListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
        if (event.timestamp == 0) return; //just ignoring for nexus 1
        sLastProximitySensorValueNearby = isProximitySensorNearby(event);
        proximityNearbyChanged();
        }
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {}
    };


    private static void simulateProximitySensorNearby(Activity activity, boolean nearby) {
    final Window window = activity.getWindow();
    WindowManager.LayoutParams params = window.getAttributes();
    View view = ((ViewGroup) window.getDecorView().findViewById(android.R.id.content)).getChildAt(0);
    if (nearby) {
            params.screenBrightness = 0.1f;
            view.setVisibility(View.INVISIBLE);
            Compatibility.hideNavigationBar(activity);
    } else  {
        params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
            view.setVisibility(View.VISIBLE);
            Compatibility.showNavigationBar(activity);
    }
        window.setAttributes(params);
    }

    private static void proximityNearbyChanged() {
    boolean nearby = sLastProximitySensorValueNearby;
    for (Activity activity : sProximityDependentActivities) {
        simulateProximitySensorNearby(activity, nearby);
    }
    }

    public static synchronized void startProximitySensorForActivity(Activity activity) {
    if (sProximityDependentActivities.contains(activity)) {
        Log.i("proximity sensor already active for " + activity.getLocalClassName());
        return;
    }
    if (sProximityDependentActivities.isEmpty()) {
        SensorManager sm = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
        Sensor s = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
        if (s != null) {
        sm.registerListener(sProximitySensorListener,s,SensorManager.SENSOR_DELAY_UI);
        Log.i("Proximity sensor detected, registering");
        }
    } else if (sLastProximitySensorValueNearby){
        simulateProximitySensorNearby(activity, true);
    }

    sProximityDependentActivities.add(activity);
    }

    public static synchronized void stopProximitySensorForActivity(Activity activity) {
    sProximityDependentActivities.remove(activity);
    simulateProximitySensorNearby(activity, false);
    if (sProximityDependentActivities.isEmpty()) {
        SensorManager sm = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
        sm.unregisterListener(sProximitySensorListener);
        sLastProximitySensorValueNearby = false;
    }
    }


    /**  如果LinphoneManager实例对象都为空,当然获取的是null了*/
    public static synchronized LinphoneCore getLcIfManagerNotDestroyedOrNull() {
    if (sExited || instance == null) {
        // Can occur if the UI thread play a posted event but in the meantime the LinphoneManager was destroyed
        // Ex: stop call and quickly terminate application.
        Log.w("Trying to get linphone core while LinphoneManager already destroyed or not created");
        return null;
    }
    return getLc();
    }

    public static final boolean isInstanciated() {
    return instance != null;
    }

    public synchronized LinphoneCall getPendingIncomingCall() {
    LinphoneCall currentCall = mLc.getCurrentCall();
    if (currentCall == null) return null;

    LinphoneCall.State state = currentCall.getState();
    boolean incomingPending = currentCall.getDirection() == CallDirection.Incoming
        && (state == State.IncomingReceived || state == State.CallIncomingEarlyMedia);

    return incomingPending ? currentCall : null;
    }




    @SuppressWarnings("serial")
    public static class LinphoneConfigException extends LinphoneException {

    public LinphoneConfigException() {
        super();
    }

    public LinphoneConfigException(String detailMessage, Throwable throwable) {
        super(detailMessage, throwable);
    }

    public LinphoneConfigException(String detailMessage) {
        super(detailMessage);
    }

    public LinphoneConfigException(Throwable throwable) {
        super(throwable);
    }
    }

    @Override
    public void notifyReceived(LinphoneCore lc, LinphoneCall call,
                   LinphoneAddress from, byte[] event) {
    }
    @Override
    public void transferState(LinphoneCore lc, LinphoneCall call,
                  State new_call_state) {

    }
    @Override
    public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) {
    Log.d("Info message received from "+call.getRemoteAddress().asString());
    LinphoneContent ct=info.getContent();
    if (ct!=null){
        Log.d("Info received with body with mime type "+ct.getType()+"/"+ct.getSubtype()+" and data ["+ct.getDataAsString()+"]");
    }
    }
    @Override
    public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev,
                     SubscriptionState state) {
    Log.d("Subscription state changed to "+state+" event name is "+ev.getEventName());
    }

    @Override
    public void notifyReceived(LinphoneCore lc, LinphoneEvent ev,
                   String eventName, LinphoneContent content) {
    Log.d("Notify received for event "+eventName);
    if (content!=null) Log.d("with content "+content.getType()+"/"+content.getSubtype()+" data:"+content.getDataAsString());
    }
    @Override
    public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev,
                    PublishState state) {
    Log.d("Publish state changed to " + state + " for event name " + ev.getEventName());
    }

    @Override
    public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) {
    Log.d("Composing received for chatroom " + cr.getPeerAddress().asStringUriOnly());
    }
    //配置的状态
    @Override
    public void configuringStatus(LinphoneCore lc,
                  RemoteProvisioningState state, String message) {
    Log.d("Remote provisioning status = " + state.toString() + " (" + message + ")");

    if (state == RemoteProvisioningState.ConfiguringSuccessful) {
        if (LinphonePreferences.instance().isProvisioningLoginViewEnabled()) {
        LinphoneProxyConfig proxyConfig = lc.createProxyConfig();
        try {
            LinphoneAddress addr = LinphoneCoreFactory.instance().createLinphoneAddress(proxyConfig.getIdentity());
            wizardLoginViewDomain = addr.getDomain();
        } catch (LinphoneCoreException e) {
            wizardLoginViewDomain = null;
        }
        }
    }
    }
    @Override
    public void fileTransferProgressIndication(LinphoneCore lc,
                           LinphoneChatMessage message, LinphoneContent content, int progress) {

    }
    @Override
    public void fileTransferRecv(LinphoneCore lc, LinphoneChatMessage message,
                 LinphoneContent content, byte[] buffer, int size) {

    }
    @Override
    public int fileTransferSend(LinphoneCore lc, LinphoneChatMessage message,
                LinphoneContent content, ByteBuffer buffer, int size) {
    return 0;
    }

    @Override
    public void uploadProgressIndication(LinphoneCore linphoneCore, int offset, int total) {
    if(total > 0)
        Log.d("Log upload progress: currently uploaded = " + offset + " , total = " + total + ", % = " + String.valueOf((offset * 100) / total));
    }

    @Override
    public void uploadStateChanged(LinphoneCore linphoneCore, LogCollectionUploadState state, String info) {
    Log.d("Log upload state: " + state.toString() + ", info = " + info);

    if (state == LogCollectionUploadState.LogCollectionUploadStateDelivered) {
        LinphoneActivity.instance().sendLogs(LinphoneService.instance().getApplicationContext(),info);
    }
    }

    @Override
    public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,
                    int delay_ms, Object data) {
    // TODO Auto-generated method stub

    }

    @Override
    public void friendListCreated(LinphoneCore lc, LinphoneFriendList list) {
    // TODO Auto-generated method stub
    }

    @Override
    public void friendListRemoved(LinphoneCore lc, LinphoneFriendList list) {
    // TODO Auto-generated method stub
    }
}


标签:mLc,null,java,void,return,LinphoneManager,import,linphone,public
From: https://blog.51cto.com/u_11797608/6371450

相关文章

  • Java中如何获得A<T>泛型中T的运行时类型及原理探究(转)
    原文:https://developer.aliyun.com/article/1226646简介如果经常写工具类,很大概率会遇到一个比较实际的问题,就是需要在泛型表达式A中获取T的运行时类型。获取它需要一些技巧。但这个技巧很少被透彻的解释过为什么会生效。在接下来的文章里,我们会从Java的泛型(Generics)谈起,结合JLS......
  • JAVA restemplate 通过application/x-www-form-urlencoded访问
    试了好几种方法都不行,要么返回空,要么报错。最后就这种方法可以返回数据。MultiValueMap<String,Object>psp=newLinkedMultiValueMap<>();psp.add("aaa","xxxxx");psp.add("bbb","xxxxxxxxxxxxx");psp.add(&quo......
  • Java-Day-24( 文件 + IO流 )
    Java-Day-24文件文件就是保存数据的地方文件流文件在程序中是以流的形式来操作的流:数据在数据源(文件)和程序(内存)之间经历的路程输入流:数据从数据源(文件)到程序(内存)的路径输出流:数据从程序(内存)到数据源(文件)的路径java程序......
  • java安装授信证书
    将对方发给我们的证书上传到主机某个目录,执行如下命令:keytool-importcert-aliaswh-keystore/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.272.b10-1.el7_9.x86_64/jre/lib/security/cacerts-file./1.cer之后提示输入密码,输入changeit即可。ps:这是2023年5月25号乌行更换证......
  • linphone-去掉HistoryListFragment界面
    说明HistoryListFragment界面包括:1.拨打电话记录2.未接听记录3.修改记录看图HistoryListFragment主界面修改拨打记录界面好,开始去掉这个界面需要分析的点每次拨打记录是怎样形成的。记录还可以分日期显示一组。没有接到的电话是怎样记录的就该记录时,那个工具栏是怎样变......
  • linphone-自动接听视频电话
    说明由于一定场合,需要需要自动接听视频。这时候linphone在Settings->VIDEO中勾选EnableVideo选项就可以实现自动接听视频选项了。在SettingsFragment.java中findPreference(getString(R.string.pref_video_enable_key)).setOnPreferenceChangeListener(newOnPreferenceChangeList......
  • Linphone Use WIFI only
    说明因为在移动网络下,如果输入错误的网址,会发生崩溃的情况,所以极大的可能使用了WIFI,就是在每次通话的时候都要检查是否网络可达.UseWIFIonly在每次检查的时候,去检查配置文件.这个是在.linphonerc配置文件中能够//NetworksettingspublicvoidsetWifiOnlyEnabled(B......
  • linphone 手机上不能接听电话
    问题描述这几天遇到一个问题,linphone安装到手机上不能接听电话.解决办法在linphone的设置中,设置端口号为5060,不要使用随机的端口号.然后问题就解决了.具体位置......
  • Linphone callState 电话状态的监听状态(二)
    LinphonecallState电话状态的监听状态callState是一个观察者模式接着上一篇的说,这篇主要是涉及到linphone中c层的注册监听机制.主要是代码追踪和代码过程.linphonecore_jni.cc中的添加监听事件的方法linphonecore_jni.cc中extern"C"voidJava_org_linphone_core_LinphoneC......
  • Linphone callState 电话状态的监听状态(一)
    0.阅读指南因为粘贴的代码比较多,阅读之前请先看目录.如果对这篇文章有什么建议的话,请在评论中指出.尽量把文章写好点.1.说明LinphoneService有个重要的机制,就是通过注册LinphoneCoreListener的实例,当Linphone的状态发声变化的时候,会回调相应的方法.然后linphone上层......