介绍

本篇主要是对个人对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.javaCopyright (C) 2010  Belledonne Communications, Grenoble, FranceThis program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, 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;}@Overridepublic 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);}}@Overridepublic void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer) {}/**  发送数据*/@Overridepublic 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() + ")");}}}/**  通知每一个回调,文件传输发生的变化*/@Overridepublic 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 streamreturn;}} 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 initializationboolean 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() {@Overridepublic void run() {UIThreadDispatcher.dispatch(new Runnable() {@Overridepublic 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 availableif (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 crashChatStorage.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设置为offlinepublic 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 reachableI/Linphone( 8397): new state [RegistrationProgress]I/Linphone( 8397): mobile disconnected: setting network unreachableI/Linphone( 8397): Managing tunnelI/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) {}@Overridepublic void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {Log.d("DTMF received: " + dtmf);}//接收消息处理消息的类@Overridepublic 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 secondsif (mLc.getCallsNb() == 1) {BluetoothManager.getInstance().disableBluetoothSCO(); // Just in caseringingCall = call;startRinging();// otherwise there is the beep}} else if (call == ringingCall && isRinging) {//previous state was ringing, so stop ringingstopRinging();}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 usedmHandler.postDelayed(new Runnable() {@Overridepublic 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 methodif (!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 streammAudioManager.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 nearfinal 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 sensorsthreshold = maxDistance;}return distanceInCm < threshold;}private static boolean sLastProximitySensorValueNearby;private static Set<Activity> sProximityDependentActivities = new HashSet<Activity>();private static SensorEventListener sProximitySensorListener = new SensorEventListener() {@Overridepublic void onSensorChanged(SensorEvent event) {if (event.timestamp == 0) return; //just ignoring for nexus 1sLastProximitySensorValueNearby = isProximitySensorNearby(event);proximityNearbyChanged();}@Overridepublic 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);}}@Overridepublic void notifyReceived(LinphoneCore lc, LinphoneCall call,LinphoneAddress from, byte[] event) {}@Overridepublic void transferState(LinphoneCore lc, LinphoneCall call,State new_call_state) {}@Overridepublic 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()+"]");}}@Overridepublic void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev,SubscriptionState state) {Log.d("Subscription state changed to "+state+" event name is "+ev.getEventName());}@Overridepublic 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());}@Overridepublic void publishStateChanged(LinphoneCore lc, LinphoneEvent ev,PublishState state) {Log.d("Publish state changed to " + state + " for event name " + ev.getEventName());}@Overridepublic void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) {Log.d("Composing received for chatroom " + cr.getPeerAddress().asStringUriOnly());}//配置的状态@Overridepublic 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;}}}}@Overridepublic void fileTransferProgressIndication(LinphoneCore lc,LinphoneChatMessage message, LinphoneContent content, int progress) {}@Overridepublic void fileTransferRecv(LinphoneCore lc, LinphoneChatMessage message,LinphoneContent content, byte[] buffer, int size) {}@Overridepublic int fileTransferSend(LinphoneCore lc, LinphoneChatMessage message,LinphoneContent content, ByteBuffer buffer, int size) {return 0;}@Overridepublic 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));}@Overridepublic 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);}}@Overridepublic void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {// TODO Auto-generated method stub}@Overridepublic void friendListCreated(LinphoneCore lc, LinphoneFriendList list) {// TODO Auto-generated method stub}@Overridepublic void friendListRemoved(LinphoneCore lc, LinphoneFriendList list) {// TODO Auto-generated method stub}
}

linphone-LinphoneManager.java文件分析相关推荐

  1. java class 文件分析_大概优秀的java程序员都要会分析class文件吧

    相信大家在学java的时候都会听到这样的一些结论: enum 是一个类 泛型的实现使用了类型擦除技术 非静态内部类持有外部类的引用 需要将自由变量声明成final才能给匿名内部类访问 ... 初学的时 ...

  2. Java C#分析WAV音频文件1Khz是否有声音

    本文是用Java写的,C#原理一样并已经验证 最近工作需要检测设备的是否有音频输出,找了很多资料,但是关于1Khz的验证并没有多少,所以我就自己查WAV的文件格式,并手撸了代码,来检测是否1Khz有声 ...

  3. Java Heap dump文件分析工具jhat简介

    jhat 是Java堆分析工具(Java heap Analyzes Tool). 在JDK6u7之后成为标配. 使用该命令需要有一定的Java开发经验,官方不对此工具提供技术支持和客户服务. 用法: ...

  4. Java的dump文件分析及JProfiler使用

    Java的dump文件分析及JProfiler使用 1 dump文件介绍 从软件开发的角度上,dump文件就是当程序产生异常时,用来记录当时的程序状态信息(例如堆栈的状态),用于程序开发定位问题. i ...

  5. java heap分析工具_Java Heap dump文件分析工具jhat简介

    [开发.应用中老是会遇到OutOfMemory异常,而且常常是过一段时间内存才被吃光,这里可以利用java heap dump出jvm内存镜像,然后再对其进行分析来查找问题.<java heap ...

  6. java class dex_class文件与dex文件分析

    1.什么是class文件 class文件就是可以被JVM识别,加载,运行的一种文件格式.一般情况下,它可以由java代码编译执行后得到,但是这并不是一定的,像kotlin,scala,python,r ...

  7. java dump分析工具_java性能分析与常用工具

    本次源码已放在Github:https://github.com/nateshao/jvm-tuning 个人博客 https://nateshao.gitee.io http://www.nates ...

  8. Android JNI入门第四篇——jni头文件分析

    转载请标明出处: http://blog.csdn.net/michael1112/article/details/56666407 江东橘子的博客 一. 首先写了java文件: public cla ...

  9. 工程是.java文件_1.8 工程相关解析(各种文件,资源访问)

    本节引言: 前面讲了一堆看似和我们Android开发无关的东西是吧,当然是现在看似而已,以后你回头看就知道了! 好吧,本节我们就来以前面创建的Hello World项目为入口,来了解工程结构, 以及A ...

最新文章

  1. Server 2012 Hyper-v新功能之一:客户端 Hyper-V
  2. 计算机中cmos设置程序,电脑主板上有CMOS设置是什么意思
  3. 配置网络测试环境的批处理
  4. 水塔清洗机器人_最全的中央空调清洗流程
  5. 编程新手选择开发语言的注意事项
  6. java中mouselistener的用法_关于MouseListener接口的简单使用
  7. Day01 爬虫基本原理及requests请求库
  8. Kejin Game UVALive - 7264 (最大流转最小割)
  9. smart210 资源
  10. 硬盘绝密维修资料!--2
  11. 因子分析(FA)算法简述
  12. Windows 适配 Apple Magic TrackPad2
  13. Qt的http下载的Demo
  14. C++和VC++学习方法
  15. 30 个纯 HTML5 实现的游戏
  16. 后台服务架构高性能设计之道
  17. 基于kali的一次无线渗透测试
  18. 人手必备,策略中最常用的5类Python数据接口
  19. iOS开发者如何分配利用好自己的时间去进阶
  20. 【技术备忘录】广和通ADP-L610-Arduino模块实现基于内网穿透的TCP通信

热门文章

  1. 关闭Flash广告弹窗( FF新鲜事 )
  2. 安装Anaconda3
  3. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
  4. Status Bar Style是干什么的?
  5. STM32定时器—PWM 输出
  6. 机器学习中的数学——点估计(四):最大后验估计(Maximum Posteriori Probability,MAP)
  7. 最全overleaf在线编辑数学公式以及遇到错误的解决方法!
  8. 谷歌浏览器视频播放加速代码
  9. python视频识别_视频人员行为识别(Action Recognition)
  10. 为什么很多编程语言中数组都从0开始编号