linphone源码研究之callState回调——无法及时获取sip消息中正确的AudioDirection和VideoDirection

本文详细记录了研究linphone源码过程中遇到的问题,即在callState回调中无法及时获取sip消息中的AudioDirection和VideoDirection。作者通过分析源码,发现只有在stream running时才能得到真实值,而之前的outgoing call和call in progress等状态获取到的都是默认的SendRecv。文章深入到C源码层面,揭示了回调机制和媒体方向设置的过程,为解决这个问题提供了思路。
摘要由CSDN通过智能技术生成

需要准备的材料:

1.liphone4android-master代码,此代码已经编译过,可直接运行到手机上

需要的伙伴可以自行下载:

https://github.com/treasure-lau/Linphone4Android

2.linphone-3.11.1,此代码为linphone底层源码,在linphone官网下载即可

这里项目代码和C源码并不是用一个版本,项目为3.10.2版本的源码。

配置和服务器,我就不多说了

本公司曾经外包给别人过一套sip消息外加编解码的底层项目给别人,长期的代码维护和沟通上的问题不停出现,公司终于决定,抛弃原始底层,改用linphone的底层来实现网络视频电话。于是,这个光荣而又极其需要头发的任务,就落在了公司本人身上。

第一次运行源码,百度了不少,终于找到了在藏在LinphoneService,java文件下的callState回调,在此回调中,可及时的获取呼叫的状态。

/*
LinphoneService.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package org.linphone;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.view.WindowManager;

import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCallLog.CallStatus;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreFactoryImpl;
import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.PayloadType;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
import org.linphone.ui.LinphoneOverlay;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * 
 * Linphone service, reacting to Incoming calls, ...<br />
 * 
 * Roles include:<ul>
 * <li>Initializing LinphoneManager</li>
 * <li>Starting C libLinphone through LinphoneManager</li>
 * <li>Reacting to LinphoneManager state changes</li>
 * <li>Delegating GUI state change actions to GUI listener</li>
 * 
 * 
 * @author Guillaume Beraudo
 *
 */
public final class LinphoneService extends Service {
	/* Listener needs to be implemented in the Service as it calls
	 * setLatestEventInfo and startActivity() which needs a context.
	 */
	public static final String START_LINPHONE_LOGS = " ==== Phone information dump ====";
	public static final int IC_LEVEL_ORANGE=0;
	/*private static final int IC_LEVEL_GREEN=1;
	private static final int IC_LEVEL_RED=2;*/
	//public static final int IC_LEVEL_OFFLINE=3;
	
	private static LinphoneService instance;
	
	private final static int NOTIF_ID=1;
	private final static int INCALL_NOTIF_ID=2;
	private final static int MESSAGE_NOTIF_ID=3;
	private final static int CUSTOM_NOTIF_ID=4;
	private final static int MISSED_NOTIF_ID=5;

	/**
	 * 返回服务是否准备好
	 * @return
     */
	public static boolean isReady() {
		return instance != null && instance.mTestDelayElapsed;
	}

	/**
	 * 返回linphone服务的对象,若还未创建,则抛出异常
	 * @throws RuntimeException service not instantiated
	 */
	public static LinphoneService instance()  {
		if (isReady()) return instance;

		throw new RuntimeException("LinphoneService not instantiated yet");
	}

	public Handler mHandler = new Handler();

//	private boolean mTestDelayElapsed; // add a timer for testing
	/**
	 * 测试延长时间,不设置
	 */
	private boolean mTestDelayElapsed = true; // no timer
	/**
	 * 通知栏管理器
	 */
	private NotificationManager mNM;
	private Notification mNotif;
	private Notification mIncallNotif;
	private Notification mMsgNotif;
	private Notification mCustomNotif;
	private int mMsgNotifCount;
	private PendingIntent mNotifContentIntent, mMissedCallsNotifContentIntent;
	private String mNotificationTitle;
	private boolean mDisableRegistrationStatus;
	/**
	 * linphone 底层回调接口,监听电话呼叫状态的改变
	 */
	private LinphoneCoreListenerBase mListener;
	public static int notifcationsPriority = (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41) ? Notification.PRIORITY_MIN : 0);
	private WindowManager mWindowManager;
	private LinphoneOverlay mOverlay;
	private Application.ActivityLifecycleCallbacks activityCallbacks;



	/*Believe me or not, but knowing the application visibility state on Android is a nightmare.
	After two days of hard work I ended with the following class, that does the job more or less reliabily.
	*/

	/**
	 * linphone码农吐槽部分,监听界面的可见情况
	 */
	class ActivityMonitor implements Application.ActivityLifecycleCallbacks {
		private ArrayList<Activity> activities = new ArrayList<Activity>();
		private boolean mActive = false;
		private int mRunningActivities = 0;

		class InactivityChecker implements Runnable {
			private boolean isCanceled;

			public void cancel() {
				isCanceled = true;
			}

			@Override
			public void run() {
				synchronized(LinphoneService.this) {
					if (!isCanceled) {
						if (ActivityMonitor.this.mRunningActivities == 0 && mActive) {
							mActive = false;
							LinphoneService.this.onBackgroundMode();
						}
					}
				}
			}
		};

		private InactivityChecker mLastChecker;

		@Override
		public synchronized void onActivityCreated(Activity activity, Bundle savedInstanceState) {
			Log.i("Activity created:" + activity);
			if (!activities.contains(activity))
				activities.add(activity);
		}

		@Override
		public void onActivityStarted(Activity activity) {
			Log.i("Activity started:" + activity);
		}

		@Override
		public synchronized void onActivityResumed(Activity activity) {
			Log.i("Activity resumed:" + activity);
			if (activities.contains(activity)) {
				mRunningActivities++;
				Log.i("runningActivities=" + mRunningActivities);
				checkActivity();
			}

		}

		@Override
		public synchronized void onActivityPaused(Activity activity) {
			Log.i("Activity paused:" + activity);
			if (activities.contains(activity)) {
				mRunningActivities--;
				Log.i("runningActivities=" + mRunningActivities);
				checkActivity();
			}

		}

		@Override
		public void onActivityStopped(Activity activity) {
			Log.i("Activity stopped:" + activity);
		}

		@Override
		public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

		}

		@Override
		public synchronized void onActivityDestroyed(Activity activity) {
			Log.i("Activity destroyed:" + activity);
			if (activities.contains(activity)) {
				activities.remove(activity);
			}
		}

		void startInactivityChecker() {
			if (mLastChecker != null) mLastChecker.cancel();
			LinphoneService.this.mHandler.postDelayed(
					(mLastChecker = new InactivityChecker()), 2000);
		}

		void checkActivity() {

			if (mRunningActivities == 0) {
				if (mActive) startInactivityChecker();
			} else if (mRunningActivities > 0) {
				if (!mActive) {
					mActive = true;
					LinphoneService.this.onForegroundMode();
				}
				if (mLastChecker != null) {
					mLastChecker.cancel();
					mLastChecker = null;
				}
			}
		}
	}

	/**
	 * 进入后台模式
	 */
	protected void onBackgroundMode(){
		Log.i("App has entered background mode");
		if (LinphonePreferences.instance() != null && LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
			if (LinphoneManager.isInstanciated())
				LinphoneManager.getInstance().subscribeFriendList(false);
		}
	}

	/**
	 * 前台模式
	 */
	protected void onForegroundMode() {
		Log.i("App has left background mode");
	}

	private void setupActivityMonitor(){
		if (activityCallbacks != null) return;
		getApplication().registerActivityLifecycleCallbacks(activityCallbacks = new ActivityMonitor());
	}

	public int getMessageNotifCount() {
		return mMsgNotifCount;
	}
	
	public void resetMessageNotifCount() {
		mMsgNotifCount = 0;
	}
	
	private boolean displayServiceNotification() {
		return LinphonePreferences.instance().getServiceNotificationVisibility();
	}
	
	public void showServiceNotification() {
		startForegroundCompat(NOTIF_ID, mNotif);
		
		LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
		if (lc == null) return;
		LinphoneProxyConfig lpc = lc.getDefaultProxyConfig();
		if (lpc != null) {
			if (lpc.isRegistered()) {
				sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered);
			} else {
				sendNotification(IC_LEVEL_ORANGE, R.string.notification_register_failure);
			}
		} else {
			sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
		}
	}
	
	public void hideServiceNotification() {
		stopForegroundCompat(NOTIF_ID);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void onCreate() {
		super.onCreate();

		setupActivityMonitor();
		// In case restart after a crash. Main in LinphoneActivity
		mNotificationTitle = getString(R.string.service_name);

		// Needed in order for the two next calls to succeed, libraries must have been loaded first
		/*下面两个调用成功,必须先加载库*/
		LinphonePreferences.instance().setContext(getBaseContext());
		LinphoneCoreFactory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath());
		boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
		LinphoneCoreFactory.instance().enableLogCollection(isDebugEnabled);
		LinphoneCoreFactory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name));
		
		// Dump some debugging information to the logs
		Log.i(START_LINPHONE_LOGS);
		dumpDeviceInformation();
		dumpInstalledLinphoneInformation();

		mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		/*解决在崩溃的情况下,图标不会删除的情况*/
		mNM.cancel(INCALL_NOTIF_ID); // in case of crash the icon is not removed

		Intent notifIntent = new Intent(this, incomingReceivedActivity);
		notifIntent.putExtra("Notification", true);
		mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
		
		Intent missedCallNotifIntent = new Intent(this, incomingReceivedActivity);
		missedCallNotifIntent.putExtra("GoToHistory", true);
		mMissedCallsNotifContentIntent = PendingIntent.getActivity(this, 0, missedCallNotifIntent, PendingIntent.FLAG_UPDATE_CURRENT);

		Bitmap bm = null;
		try {
			bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
		} catch (Exception e) {
		}
		mNotif = Compatibility.createNotification(this, mNotificationTitle, "", R.drawable.linphone_notification_icon, R.mipmap.ic_launcher, bm, mNotifContentIntent, true,notifcationsPriority);

		LinphoneManager.createAndStart(LinphoneService.this);

		instance = this; // instance is ready once linphone manager has been created
		incomingReceivedActivityName = LinphonePreferences.instance().getActivityToLaunchOnIncomingReceived();
		try {
			incomingReceivedActivity = (Class<? extends Activity>) Class.forName(incomingReceivedActivityName);
		} catch (ClassNotFoundException e) {
			Log.e(e);
		}
		
		LinphoneManager.getLc().addListener(mListener = new LinphoneCoreListenerBase() {
			@Override
			public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
				String TAG = "LinphoneService";
				android.util.Log.e(TAG,"LinphoneCall.State--state:"+state);
				android.util.Log.e(TAG,"message:"+message);
				android.util.Log.e(TAG,"MaxCalls:"+lc.getMaxCalls());
				android.util.Log.e(TAG,"--------------------------------------------------------------");
				for (final PayloadType pt : lc.getAudioCodecs()) {
					android.util.Log.e(TAG,"LinphoneCore-"+pt.getMime()+"-Rate-"+pt.getRate()+"-open:"+lc.isPayloadTypeEnabled(pt));
				}
				android.util.Log.e(TAG,"--------------------------------------------------------------");
				android.util.Log.e(TAG,"LinphoneCore--AudioDirection:"+lc.getCurrentCall().getCurrentParamsCopy().getAudioDirection());
				android.util.Log.e(TAG,"LinphoneCore--VideoDirection:"+lc.getCurrentCall().getCurrentParamsCopy().getVideoDirection());

				android.util.Log.e(TAG,"--------------------------------------------------------------");

				android.util.Log.e(TAG,"LinphoneCall--AuthenticationToken:"+call.getAuthenticationToken());
				android.util.Log.e(TAG,"LinphoneCall--RemoteContact:"+call.getRemoteContact());
				android.util.Log.e(TAG,"LinphoneCall--RemoteUserAgent:"+call.getRemoteUserAgent());
				android.util.Log.e(TAG,"LinphoneCall--AudioStats:"+call.getAudioStats());
				if (call.getAudioStats()!=null) {
					android.util.Log.e(TAG, "LinphoneCall--AudioStats--MediaType:" + call.getAudioStats().getMediaType());
					android.util.Log.e(TAG, "LinphoneCall--AudioStats--IceState:" + call.getAudioStats().getIceState());
				}
				android.util.Log.e(TAG,"LinphoneCall--VideoStats:"+call.getVideoStats());
				if (call.getVideoStats()!=null) {
					android.util.Log.e(TAG,"LinphoneCall--VideoStats--MediaType:"+call.getVideoStats().getMediaType());
					android.util.Log.e(TAG,"LinphoneCall--VideoStats--IceState:"+call.getVideoStats().getIceState());
				}
				android.util.Log.e(TAG,"LinphoneCall--AverageQuality:"+call.getAverageQuality());
				android.util.Log.e(TAG,"--------------------------------------------------------------");

				android.util.Log.e(TAG, "LinphoneCall--CallLog:" + call.getCallLog());
				if (call.getCallLog()!= null) {
					android.util.Log.e(TAG, "LinphoneCall--CallLog--CallId:" + call.getCallLog().getCallId());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--StartDate:" + call.getCallLog().getStartDate());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--Timestamp:" + call.getCallLog().getTimestamp());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--CallDuration():" + call.getCallLog().getCallDuration());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--Direction:" + call.getCallLog().getDirection());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--From--DisplayName:" + call.getCallLog().getFrom().getDisplayName());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--From--Domain:" + call.getCallLog().getFrom().getDomain());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--From--UserName:" + call.getCallLog().getFrom().getUserName());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--From--Port:" + call.getCallLog().getFrom().getPort());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--From--Transport:" + call.getCallLog().getFrom().getTransport());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--To--DisplayName:" + call.getCallLog().getTo().getDisplayName());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--To--Domain:" + call.getCallLog().getTo().getDomain());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--To--UserName:" + call.getCallLog().getTo().getUserName());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--To--Port:" + call.getCallLog().getTo().getPort());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--To--Transport:" + call.getCallLog().getTo().getTransport());
					android.util.Log.e(TAG, "LinphoneCall--CallLog--Status:" + call.getCallLog().getStatus());
					android.util.Log.e(TAG, "--------------------------------------------------------------");
				}

				android.util.Log.e(TAG, "LinphoneCall--ChatRoom:" + call.getChatRoom());
				if (call.getChatRoom()!= null) {
					android.util.Log.e(TAG, "LinphoneCall--ChatRoom--PeerAddress--DisplayName:" + call.getChatRoom().getPeerAddress()
							.getDisplayName());
					android.util.Log.e(TAG, "LinphoneCall--ChatRoom--PeerAddress--Domain:" + call.getChatRoom().getPeerAddress().getDomain());
					android.util.Log.e(TAG, "LinphoneCall--ChatRoom--PeerAddress--UserName:" + call.getChatRoom().getPeerAddress().getUserName());
					android.util.Log.e(TAG, "LinphoneCall--ChatRoom--PeerAddress--Port:" + call.getChatRoom().getPeerAddress().getPort());
					android.util.Log.e(TAG, "LinphoneCall--ChatRoom--PeerAddress--Transport:" + call.getChatRoom().getPeerAddress().getTransport());
					android.util.Log.e(TAG, "--------------------------------------------------------------");
				}
				android.util.Log.e(TAG, "LinphoneCall--Conference:" + call.getConference());
				if (call.getConference()!= null) {
					android.util.Log.e(TAG, "LinphoneCall--Conference--Participants:" + call.getConference().getParticipants().length);
				}
				android.util.Log.e(TAG,"LinphoneCall--CurrentQuality:"+call.getCurrentQuality());
				android.util.Log.e(TAG,"LinphoneCall--Direction:"+call.getDirection());
				android.util.Log.e(TAG,"--------------------------------------------------------------");

				android.util.Log.e(TAG, "LinphoneCall--DiversionAddress:" + call.getDiversionAddress());
				if (call.getDiversionAddress()!= null) {
					android.util.Log.e(TAG, "LinphoneCall--DiversionAddress--DisplayName:" + call.getDiversionAddress().getDisplayName());
					android.util.Log.e(TAG, "LinphoneCall--DiversionAddress--Domain:" + call.getDiversionAddress().getDomain());
					android.util.Log.e(TAG, "LinphoneCall--DiversionAddress--UserName:" + call.getDiversionAddress().getUserName());
					android.util.Log.e(TAG, "LinphoneCall--DiversionAddress--Port:" + call.getDiversionAddress().getPort());
					android.util.Log.e(TAG, "LinphoneCall--DiversionAddress--Transport:" + call.getDiversionAddress().getTransport());
					android.util.Log.e(TAG, "--------------------------------------------------------------");
				}

				if (call.getErrorInfo()!= null) {
					android.util.Log.e(TAG, "LinphoneCall--ErrorInfo--Details:" + call.getErrorInfo().getDetails());
					android.util.Log.e(TAG, "LinphoneCall--ErrorInfo--Phrase:" + call.getErrorInfo().getPhrase());
					android.util.Log.e(TAG, "LinphoneCall--ErrorInfo--ProtocolCode:" + call.getErrorInfo().getProtocolCode());
					android.util.Log.e(TAG, "LinphoneCall--ErrorInfo--Reason:" + call.getErrorInfo().getReason());
					android.util.Log.e(TAG, "--------------------------------------------------------------");
				}

				android.util.Log.e(TAG,"LinphoneCall--Player--State:"+call.getPlayer().getState());
				android.util.Log.e(TAG,"LinphoneCall--PlayVolume:"+call.getPlayVolume());
				android.util.Log.e(TAG,"LinphoneCall--Reason:"+call.getReason());
				android.util.Log.e(TAG,"--------------------------------------------------------------");
				android.util.Log.e(TAG,"LinphoneCall--RemoteAddress:"+call.getRemoteAddress());
				if (call.getRemoteAddress() != null) {
					android.util.Log.e(TAG, "LinphoneCall--RemoteAddress--DisplayName:" + call.getRemoteAddress().getDisplayName());
					android.util.Log.e(TAG, "LinphoneCall--RemoteAddress--Domain:" + call.getRemoteAddress().getDomain());
					android.util.Log.e(TAG, "LinphoneCall--RemoteAddress--UserName:" + call.getRemoteAddress().getUserName());
					android.util.Log.e(TAG, "LinphoneCall--RemoteAddress--Port:" + call.getRemoteAddress().getPort());
					android.util.Log.e(TAG, "LinphoneCall--RemoteAddress--Transport:" + call.getRemoteAddress().getTransport());
					android.util.Log.e(TAG, "--------------------------------------------------------------");
				}

				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--AudioDirection:"+call.getCurrentParamsCopy().getAudioDirection());
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--UsedAudioCodec:"+call.getCurrentParamsCopy().getUsedAudioCodec());
				if (call.getCurrentParamsCopy().getUsedAudioCodec() != null) {
					android.util.Log.e(TAG, "LinphoneCall--CurrentParamsCopy--UsedAudioCodec.Rate:" + call.getCurrentParamsCopy().getUsedAudioCodec
							().getRate());
					android.util.Log.e(TAG, "LinphoneCall--CurrentParamsCopy--UsedAudioCodec.Mime:" + call.getCurrentParamsCopy().getUsedAudioCodec
							().getMime());
					android.util.Log.e(TAG, "LinphoneCall--CurrentParamsCopy--UsedAudioCodec.RecvFmtp:" + call.getCurrentParamsCopy().getUsedAudioCodec
							().getRecvFmtp());
					android.util.Log.e(TAG, "LinphoneCall--CurrentParamsCopy--UsedAudioCodec.SendFmtp:" + call.getCurrentParamsCopy().getUsedAudioCodec
							().getSendFmtp());
				}
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy:"+call.getCurrentParamsCopy());
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--VideoDirection:"+call.getCurrentParamsCopy().getVideoDirection());
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--VideoEnabled:"+call.getCurrentParamsCopy().getVideoEnabled());
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--UsedVideoCodec:"+call.getCurrentParamsCopy().getUsedVideoCodec());
				if (call.getCurrentParamsCopy().getUsedVideoCodec() != null) {
					android.util.Log.e(TAG, "LinphoneCall--CurrentParamsCopy--UsedAudioCodec.Rate:" + call.getCurrentParamsCopy().getUsedVideoCodec
							().getRate());
					android.util.Log.e(TAG, "LinphoneCall--CurrentParamsCopy--UsedAudioCodec.Mime:" + call.getCurrentParamsCopy().getUsedVideoCodec
							().getMime());
					android.util.Log.e(TAG, "LinphoneCall--CurrentParamsCopy--UsedAudioCodec.RecvFmtp:" + call.getCurrentParamsCopy().getUsedVideoCodec
							().getRecvFmtp());
					android.util.Log.e(TAG, "LinphoneCall--CurrentParamsCopy--UsedAudioCodec.SendFmtp:" + call.getCurrentParamsCopy().getUsedVideoCodec
							().getSendFmtp());
				}
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--SessionName:"+call.getCurrentParamsCopy().getSessionName());
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--ReceivedVideoSize:"+call.getCurrentParamsCopy().getReceivedVideoSize());
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--SentVideoSize:"+call.getCurrentParamsCopy().getSentVideoSize());
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--MediaEncryption:"+call.getCurrentParamsCopy().getMediaEncryption());
				android.util.Log.e(TAG,"LinphoneCall--CurrentParamsCopy--Privacy:"+call.getCurrentParamsCopy().getPrivacy());
				android.util.Log.e(TAG, "--------------------------------------------------------------");

				android.util.Log.e(TAG,"LinphoneCall--RemoteParams:"+call.getRemoteParams());
				if (call.getRemoteParams() != null) {
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--AudioDirection:"+call.getRemoteParams().getAudioDirection());
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--UsedAudioCodec:"+call.getRemoteParams().getUsedAudioCodec());
					if (call.getRemoteParams().getUsedAudioCodec() != null) {
                        android.util.Log.e(TAG, "LinphoneCall--RemoteParams--UsedAudioCodec.Rate:" + call.getRemoteParams().getUsedAudioCodec
                                ().getRate());
                        android.util.Log.e(TAG, "LinphoneCall--RemoteParams--UsedAudioCodec.Mime:" + call.getRemoteParams().getUsedAudioCodec
                                ().getMime());
                        android.util.Log.e(TAG, "LinphoneCall--RemoteParams--UsedAudioCodec.RecvFmtp:" + call.getRemoteParams().getUsedAudioCodec
                                ().getRecvFmtp());
                        android.util.Log.e(TAG, "LinphoneCall--RemoteParams--UsedAudioCodec.SendFmtp:" + call.getRemoteParams().getUsedAudioCodec
                                ().getSendFmtp());
                    }
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--VideoDirection:"+call.getRemoteParams().getVideoDirection());
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--VideoEnabled:"+call.getRemoteParams().getVideoEnabled());
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--UsedVideoCodec:"+call.getRemoteParams().getUsedVideoCodec());
					if (call.getCurrentParamsCopy().getUsedVideoCodec() != null) {
                        android.util.Log.e(TAG, "LinphoneCall--RemoteParams--UsedVideoCodec.Rate:" + call.getRemoteParams().getUsedVideoCodec
                                ().getRate());
                        android.util.Log.e(TAG, "LinphoneCall--RemoteParams--UsedVideoCodec.Mime:" + call.getRemoteParams().getUsedVideoCodec
                                ().getMime());
                        android.util.Log.e(TAG, "LinphoneCall--RemoteParams--UsedVideoCodec.RecvFmtp:" + call.getRemoteParams().getUsedVideoCodec
                                ().getRecvFmtp());
                        android.util.Log.e(TAG, "LinphoneCall--RemoteParams--UsedVideoCodec.SendFmtp:" + call.getRemoteParams().getUsedVideoCodec
                                ().getSendFmtp());
                    }
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--SessionName:"+call.getRemoteParams().getSessionName());
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--ReceivedVideoSize:"+call.getRemoteParams().getReceivedVideoSize());
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--SentVideoSize:"+call.getRemoteParams().getSentVideoSize());
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--MediaEncryption:"+call.getRemoteParams().getMediaEncryption());
					android.util.Log.e(TAG,"LinphoneCall--RemoteParams--Privacy:"+call.getRemoteParams().getPrivacy());
				}
				android.util.Log.e(TAG, "--------------------------------------------------------------");

				android.util.Log.e(TAG,"LinphoneCall--ReplacedCall:"+call.getReplacedCall());
				android.util.Log.e(TAG,"LinphoneCall--TransfererCall:"+call.getTransfererCall());
				android.util.Log.e(TAG,"LinphoneCall--TransferState:"+call.getTransferState());
				android.util.Log.e(TAG,"LinphoneCall--TransferTargetCall:"+call.getTransferTargetCall());
				android.util.Log.e(TAG,"LinphoneCall--UserData:"+call.getUserData());
				android.util.Log.e(TAG,"*********************************************************************");

				if (instance == null) {
					Log.i("Service not ready, discarding call state change to ",state.toString());
					return;
				}
				
				if (state == LinphoneCall.State.IncomingReceived) {
					onIncomingReceived();
				}
				
				if (state == State.CallEnd || state == State.CallReleased || state == State.Error) {
					destroyOverlay();
				}
				
				if (state == State.CallEnd && call.getCallLog().getStatus() == CallStatus.Missed) {
					int missedCallCount = LinphoneManager.getLcIfManagerNotDestroyedOrNull().getMissedCallsCount();
					String body;
					if (missedCallCount > 1) {
						body = getString(R.string.missed_calls_notif_body).replace("%i", String.valueOf(missedCallCount));
					} else {
						LinphoneAddress address = call.getRemoteAddress();
						LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address);
						if (c != null) {
							body = c.getFullName();
						} else {
							body = address.getDisplayName();
							if (body == null) {
								body = address.asStringUriOnly();
							}
						}
					}
					Notification notif = Compatibility.createMissedCallNotification(instance, getString(R.string.missed_calls_notif_title), body, mMissedCallsNotifContentIntent);
					notifyWrapper(MISSED_NOTIF_ID, notif);
				}

				if (state == State.StreamsRunning) {
					// Workaround bug current call seems to be updated after state changed to streams running
					if (getResources().getBoolean(R.bool.enable_call_notification))
						refreshIncallIcon(call);
				} else {
					if (getResources().getBoolean(R.bool.enable_call_notification))
						refreshIncallIcon(LinphoneManager.getLc().getCurrentCall());
				}
			}
			
			@Override
			public void globalState(LinphoneCore lc,LinphoneCore.GlobalState state, String message) {
				if (state == GlobalState.GlobalOn && displayServiceNotification()) {
					sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
				}
			}

			@Override
			public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState state, String smessage) {
//				if (instance == null) {
//					Log.i("Service not ready, discarding registration state change to ",state.toString());
//					return;
//				}
				if (!mDisableRegistrationStatus) {
					if (displayServiceNotification() && state == RegistrationState.RegistrationOk && LinphoneManager.getLc().getDefaultProxyConfig() != null && LinphoneManager.getLc().getDefaultProxyConfig().isRegistered()) {
						sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered);
					}
			
					if (displayServiceNotification() && (state == RegistrationState.RegistrationFailed || state == RegistrationState.RegistrationCleared) && (LinphoneManager.getLc().getDefaultProxyConfig() == null || !LinphoneManager.getLc().getDefaultProxyConfig().isRegistered())) {
						sendNotification(IC_LEVEL_ORANGE, R.string.notification_register_failure);
					}
					
					if (displayServiceNotification() && state == RegistrationState.RegistrationNone) {
						sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
					}
				}
			}
		});
		
		// Retrieve methods to publish notification and keep Android
		// from killing us and keep the audio quality high.
		if (Version.sdkStrictlyBelow(Version.API05_ECLAIR_20)) {
			try {
				mSetForeground = getClass().getMethod("setForeground", mSetFgSign);
			} catch (NoSuchMethodException e) {
				Log.e(e, "Couldn't find foreground method");
			}
		} else {
			try {
				mStartForeground = getClass().getMethod("startForeground", mStartFgSign);
				mStopForeground = getClass().getMethod("stopForeground", mStopFgSign);
			} catch (NoSuchMethodException e) {
				Log.e(e, "Couldn't find startForeground or stopForeground");
			}
		}

		getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, ContactsManager.getInstance());

		if (displayServiceNotification()) {
			startForegroundCompat(NOTIF_ID, mNotif);
		}

		if (!mTestDelayElapsed) {
			// Only used when testing. Simulates a 5 seconds delay for launching service
			mHandler.postDelayed(new Runnable() {
				@Override public void run() {
					mTestDelayElapsed = true;
				}
			}, 5000);
		}
		
		//make sure the application will at least wakes up every 10 mn
		Intent intent = new Intent(this, KeepAliveReceiver.class);
		PendingIntent keepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
		AlarmManager alarmManager = ((AlarmManager) this.getSystemService(Context.ALARM_SERVICE));
		Compatibility.scheduleAlarm(alarmManager, AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 600000, keepAlivePendingIntent);
		
		mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
	}
	
	public void createOverlay() {
		if (mOverlay != null) destroyOverlay();
		
		LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
		if (call == null || !call.getCurrentParamsCopy().getVideoEnabled()) return;
		
		mOverlay = new LinphoneOverlay(this);
		WindowManager.LayoutParams params = mOverlay.getWindowManagerLayoutParams();
		params.x = 0;
		params.y = 0;
		mWindowManager.addView(mOverlay, params);
	}
	
	public void destroyOverlay() {
		if (mOverlay != null) {
			mWindowManager.removeViewImmediate(mOverlay);
			mOverlay.destroy();
		}
		mOverlay = null;
	}

	private enum IncallIconState {INCALL, PAUSE, VIDEO, IDLE}
	private IncallIconState mCurrentIncallIconState = IncallIconStat
用户点击 用户点击 linphone linphone linphone linphone 的图标后就开始了 的图标后就开始了 的图标后就开始了 的图标后就开始了 的图标后就开始了 linphone linphone linphone linphone 软件,这时 软件,这时 软件,这时 软件,这时 软件,这时 linphoneActivity linphoneActivity linphoneActivity linphoneActivity linphoneActivity linphoneActivity linphoneActivity开始运行,它 开始运行,它 开始运行,它 开始运行,它 使 linphoneService linphoneService linphoneService linphoneService linphoneServicelinphoneServicelinphoneService 开始,并做一些 开始,并做一些 开始,并做一些 开始,并做一些 linphone linphone linphone linphone 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 帐号密码的登录操作同时引导用户进行环境变 量的设置( 量的设置( LinphonePreferencesActivity LinphonePreferencesActivity LinphonePreferencesActivityLinphonePreferencesActivity LinphonePreferencesActivityLinphonePreferencesActivityLinphonePreferencesActivityLinphonePreferencesActivity LinphonePreferencesActivity LinphonePreferencesActivity LinphonePreferencesActivity LinphonePreferencesActivity)。 环境变量都储存在 环境变量都储存在 环境变量都储存在 环境变量都储存在 sharedPreferencessharedPreferences sharedPreferencessharedPreferences sharedPreferencessharedPreferencessharedPreferencessharedPreferences sharedPreferences ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 ,它是整个工程共享的一变量池。这些环境有 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自动启回校正网络 音频和视编码设置选择,帐号密服务器自
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值