0. 阅读指南
因为粘贴的代码比较多, 阅读之前请先看目录.
如果对这篇文章有什么建议的话, 请在评论中指出. 尽量把文章写好点.
1. 说明
LinphoneService有个重要的机制, 就是通过注册LinphoneCoreListener的实例, 当Linphone的状态发声变化的时候, 会回调相应的方法. 然后linphone上层会做相应的处理.]
为了更好的分析整个linphone, 现在这个LinphoneCoreListener注册回调机制是怎么也躲不过去了.
用到的地方
图2.1是通过Android studio进行查找addListener调用的地方, 说明了, 这些方法一旦实例化, 便注册了addListener(), 一旦linphone有变化, 这些类就做做出相应的处理.
2. 回调都需要什么
2.1 LinphoneCoreListener.java
代码
直接看注释, 我中文稍微翻译一下
package org.linphone.core;
import java.nio.ByteBuffer;
/**
*
*This interface holds all callbacks that the application should implement. None is mandatory.
* 这个接口是接收回调, 但不是强制的.
*/
public interface LinphoneCoreListener {
/**
* @deprecated
* Ask the application some authentication information
**/
@Deprecated
void authInfoRequested(LinphoneCore lc, String realm, String username, String domain);
/**
* Ask the application some authentication information
* 询问一下有什么验证信息
* @param lc the LinphoneCore
* @param authInfo a LinphoneAuthInfo pre-filled with username, realm and domain values as much as possible
* @param method the type of authentication requested (HttpDigest, Tls, ...)
**/
void authenticationRequested(LinphoneCore lc, LinphoneAuthInfo authInfo, LinphoneCore.AuthMethod method);
/**
* Call stats notification
*/
void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);
/**
* Reports that a new subscription request has been received and wait for a decision.
*Status on this subscription request is notified by changing policy for this friend
* 有新的注册请求
*@param lc LinphoneCore
*@param lf LinphoneFriend corresponding to the subscriber
*@param url of the subscriber
*
*/
void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url);
/**
* Report status change for a friend previously added to LinphoneCore.
* @param lc LinphoneCore
* @param lf updated LinphoneFriend
*/
void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);
/**
* invoked when a new dtmf is received
* @param lc LinphoneCore
* @param call LinphoneCall involved in the dtmf sending
* @param dtmf value of the dtmf sent
*/
void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf);
/**
* Report Notified message received for this identity.
* @param lc LinphoneCore
* @param call LinphoneCall in case the notify is part of a dialog, may be null
* @param from LinphoneAddress the message comes from
* @param event String the raw body of the notify event.
*
*/
void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event);
/**
* Notifies progress of a call transfer.
* @param lc the LinphoneCore
* @param call the call through which the transfer was sent.
* @param new_call_state the state of the call resulting of the transfer, at the other party.
**/
void transferState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State new_call_state);
/**
* Notifies an incoming INFO message.
* @param lc the LinphoneCore.
* @param info the info message
*/
void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info);
/**
* Notifies of subscription requests state changes, including new incoming subscriptions.
* @param lc the LinphoneCore
* @param ev LinphoneEvent object representing the subscription context.
* @param state actual state of the subscription.
*/
void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, SubscriptionState state);
/**
* Notifies about outgoing generic publish states.
* @param lc the LinphoneCore
* @param ev a LinphoneEvent representing the publish, typically created by {@link LinphoneCore#publish}
* @param state the publish state
*/
void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, PublishState state);
/**
* Notifies the application that it should show up
* @deprecated
*/
@Deprecated
void show(LinphoneCore lc);
/**
* Callback that notifies various events with human readable text.
* @deprecated
*/
@Deprecated
void displayStatus(LinphoneCore lc,String message);
/**
* Callback to display a message to the user
* @deprecated
*/
@Deprecated
void displayMessage(LinphoneCore lc,String message);
/**
* Callback to display a warning to the user
* @deprecated
*/
@Deprecated
void displayWarning(LinphoneCore lc,String message);
/**
* Callback to be notified about the transfer progress.
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param progress percentage of the transfer done
*/
void fileTransferProgressIndication(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, int progress);
/**
* Callback to be notified when new data has been received
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param buffer
* @param size
*/
void fileTransferRecv(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, byte[] buffer, int size);
/**
* Callback to be notified when new data needs to be sent
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param buffer
* @param size
* @return the number of bytes written into buffer
*/
int fileTransferSend(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, ByteBuffer buffer, int size);
/**
* General State notification
* @param state LinphoneCore.State
*/
void globalState(LinphoneCore lc,LinphoneCore.GlobalState state, String message);
/**
* Registration state notification
* */
void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState state, String smessage);
/**
* Notifies the changes about the remote provisioning step
* @param lc the LinphoneCore
* @param state the RemoteProvisioningState
* @param message the error message if state == Failed
*/
void configuringStatus(LinphoneCore lc, LinphoneCore.RemoteProvisioningState state, String message);
/**
* invoked when a new linphone chat message is received
* 接收聊天信息
* @param lc LinphoneCore
* @param cr LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param message incoming linphone chat message message
*/
void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message);
/**
* invoked when a new linphone chat message is received and we cannot decrypt this
* @param lc LinphoneCore
* @param cr LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param message incoming linphone chat message message
*/
void messageReceivedUnableToDecrypted(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message);
/** Call State notification
* @param state LinphoneCall.State
*/
void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message);
/**
* Callback to display change in encryption state.
* @param encrypted true if all streams of the call are encrypted
* @param authenticationToken token like ZRTP SAS that may be displayed to user
*/
void callEncryptionChanged(LinphoneCore lc, LinphoneCall call, boolean encrypted, String authenticationToken);
/**
* Notifies of an incoming NOTIFY received.
* @param lc the linphoneCore
* @param ev a LinphoneEvent representing the subscription context for which this notify belongs, or null if it is a NOTIFY out of of any subscription.
* @param eventName the event name
* @param content content of the NOTIFY request.
*/
void notifyReceived(LinphoneCore lc, LinphoneEvent ev, String eventName, LinphoneContent content);
/**
* invoked when a composing notification is received
* @param lc LinphoneCore
* @param cr LinphoneChatRoom involved in the conversation.
*/
void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr);
/**
* Invoked when echo cancalation calibration is completed
* @param lc LinphoneCore
* @param status
* @param delay_ms echo delay
* @param data
*/
void ecCalibrationStatus(LinphoneCore lc, LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);
/**
* Callback prototype for reporting log collection upload progress indication.
*/
void uploadProgressIndication(LinphoneCore lc, int offset, int total);
/**
* Callback prototype for reporting log collection upload state change.
* @param lc LinphoneCore object
* @param state The state of the log collection upload
* @param info Additional information: error message in case of error state, URL of uploaded file in case of success.
*/
void uploadStateChanged(LinphoneCore lc, LinphoneCore.LogCollectionUploadState state, String info);
/**
* Callback prototype for reporting LinphoneFriendList creation.
* @param lc LinphoneCore object
* @param list LinphoneFriendList object
*/
void friendListCreated(LinphoneCore lc, LinphoneFriendList list);
/**
* Callback prototype for reporting LinphoneFriendList removal.
* @param lc LinphoneCore object
* @param list LinphoneFriendList object
*/
void friendListRemoved(LinphoneCore lc, LinphoneFriendList list);
}
其中, 有个地方implements这个方法
LinphoneCoreListenerBase implements LinphoneCoreListener
目的是为了, 可以随意的继承想要的方法, 而不用全部实现.
说明
这个是回调的核心方法. 提供所有需要回调的方法.
2.2 LinphoneCall.java 电话的回调状态
代码
/**
* Linphone call states
*
*/
static class State {
static private Vector<State> values = new Vector<State>();
private final int mValue;
public final int value() {return mValue;}
private final String mStringValue;
/**
* Idle
*/
public final static State Idle = new State(0,"Idle");
/**
* Incoming call received.
*/
public final static State IncomingReceived = new State(1,"IncomingReceived");
/**
* Outgoing call initialiazed.
*/
public final static State OutgoingInit = new State(2,"OutgoingInit");
/**
* Outgoing call in progress.
*/
public final static State OutgoingProgress = new State(3,"OutgoingProgress");
/**
* Outgoing call ringing.
*/
public final static State OutgoingRinging = new State(4,"OutgoingRinging");
/**
* Outgoing call early media
*/
public final static State OutgoingEarlyMedia = new State(5,"OutgoingEarlyMedia");
/**
* Connected
*/
public final static State Connected = new State(6,"Connected");
/**
* Streams running
*/
public final static State StreamsRunning = new State(7,"StreamsRunning");
/**
* Pausing
*/
public final static State Pausing = new State(8,"Pausing");
/**
* Paused
*/
public final static State Paused = new State(9,"Paused");
/**
* Resuming
*/
public final static State Resuming = new State(10,"Resuming");
/**
* Refered
*/
public final static State Refered = new State(11,"Refered");
/**
* Error
*/
public final static State Error = new State(12,"Error");
/**
* Call end
*/
public final static State CallEnd = new State(13,"CallEnd");
/**
* Paused by remote
*/
public final static State PausedByRemote = new State(14,"PausedByRemote");
/**
* The call's parameters are updated, used for example when video is asked by remote
*/
public static final State CallUpdatedByRemote = new State(15, "UpdatedByRemote");
/**
* We are proposing early media to an incoming call
*/
public static final State CallIncomingEarlyMedia = new State(16,"IncomingEarlyMedia");
/**
* We have initiated a call update. When the remote accepts the call update, state will move to StreamsRunning.
*/
public static final State CallUpdating = new State(17, "Updating");
/**
* The call object is now released.
*/
public static final State CallReleased = new State(18,"Released");
/**
* The call is updated by remote while not yet answered (SIP UPDATE in early dialog received)
*/
public static final State CallEarlyUpdatedByRemote = new State(19,"EarlyUpdatedByRemote");
/**
* We are updating the call while not yet answered (SIP UPDATE in early dialog sent)
**/
public static final State CallEarlyUpdating = new State(20,"EarlyUpdating");
private State(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static State fromInt(int value) {
for (int i=0; i<values.size();i++) {
State state = (State) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("state not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
}
说明
这个方法中包含了所有电话的状态, 比如
- IncomingReceived 接收来电
- OutgoingInit 拨出电话
- OutongingProgress 电话拨出中
- OutgoingRinging 拨出响铃中
- OutgoingEarlyMedia
- Connected
- StreamsRunning 接通中
- Paused 暂停
- Resuming
- Refered
- Error
- CallEnd
- PausedByRemote 被远方暂停
- UpdatedByRemote
- InconingEarlyMedia
- Updating
- Released
- EarlyUpdatedByRemote
- EarlyUpdating
等我看完了, 怎么有这么多方法.
2.3 LinphoneCore.GlobalState Global状态
代码
/**
* linphone core states
*/
static public class GlobalState {
static private Vector<GlobalState> values = new Vector<GlobalState>();
/**
* Off
*/
static public GlobalState GlobalOff = new GlobalState(0, "GlobalOff");
/**
* Startup
*/
static public GlobalState GlobalStartup = new GlobalState(1, "GlobalStartup");
/**
* On
*/
static public GlobalState GlobalOn = new GlobalState(2, "GlobalOn");
/**
* Shutdown
*/
static public GlobalState GlobalShutdown = new GlobalState(3, "GlobalShutdown");
/**
* Configuring
*/
static public GlobalState GlobalConfiguring = new GlobalState(4, "GlobalConfiguring");
说明
表示全局的状态
- GlobalOff
- GlobalStartup
- GlobalOn
- GlobalStudown
- GlobalConfiguring
全局的一个状态
2.4 LinphoneCoreListenerBase.java
这个是实现所有LinphoneCoreListener方法, 目的是不用实现所有的方法, 而是有目的的实现其中的某个或某几个方法.
2.5 LinphoneChatMessage.State
代码
public static class State {
static private Vector<State> values = new Vector<State>();
private final int mValue;
public final int value() {return mValue;}
private final String mStringValue;
/**
* Initial state
*/
public final static State Idle = new State(0,"Idle");
/**
* Delivery in progress
*/
public final static State InProgress = new State(1,"InProgress");
/**
* Message succesffully delivered an acknoleged by remote end point
*/
public final static State Delivered = new State(2,"Delivered");
/**
* Message was not delivered
*/
public final static State NotDelivered = new State(3,"NotDelivered");
/**
* Message was received(and acknowledged) but cannot get file from server
*/
public final static State FileTransferError = new State(4,"FileTransferError");
/**
* File transfer has been completed successfully.
*/
public final static State FileTransferDone = new State(5,"FileTransferDone");
/**
* Message successfully delivered and acknowledged to destination
*/
public final static State DeliveredToUser = new State(6,"DeliveredToUser");
/**
* Message displayed to the remote user
*/
public final static State Displayed = new State(7,"Displayed");
private State(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static State fromInt(int value) {
for (int i=0; i<values.size();i++) {
State state = (State) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("state not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
public int toInt() {
return mValue;
}
}
说明
主要是聊天中的一些状态
- Idle
- InProgress
- Delivered
- NotDelivered
- FileTransferError
- FileTransferDone
- DeliveredToUser
- Displayed
3. 逐一介绍
3.1 CallActivity.java
代码
mListener = new LinphoneCoreListenerBase() {
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {
displayMissedChats(); // 从jni获取数据, 显示在界面上
}
@Override
public void callState(LinphoneCore lc, final LinphoneCall call, LinphoneCall.State state, String message) {
LinphoneUtils._log("CallActivity#Turn", "callState(" +
"LinphoneCore lc " + lc +
", final LinphoneCall call" + call +
", LinphoneCall.State state" + state +
", String message" + message +
")");
if (LinphoneManager.getLc().getCallsNb() == 0) {
finish();
return;
}
if (state == State.IncomingReceived) {
startIncomingCallActivity();
return;
} else if (state == State.Paused || state == State.PausedByRemote || state == State.Pausing) {
LinphoneUtils._log("CallActivity", "} else if (state == State.Paused || state == State.PausedByRemote || state == State.Pausing) {");
if (LinphoneManager.getLc().getCurrentCall() != null) {
LinphoneUtils._log("CallActivity", "if (LinphoneManager.getLc().getCurrentCall() != null) enabledVideoButton(false);");
enabledVideoButton(false);
}
if (isVideoEnabled(call)) {
LinphoneUtils._log("CallActivity", "if (isVideoEnabled(call)) showAudioView()");
showAudioView();
}
} else if (state == State.Resuming) {
if (LinphonePreferences.instance().isVideoEnabled()) {
status.refreshStatusItems(call, isVideoEnabled(call));
if (call.getCurrentParamsCopy().getVideoEnabled()) {
showVideoView();
}
}
if (LinphoneManager.getLc().getCurrentCall() != null) {
enabledVideoButton(true);
}
} else if (state == State.StreamsRunning) {
LinphoneUtils._log("CallActivity", "} else if (state == State.StreamsRunning) {");
switchVideo(isVideoEnabled(call));
enableAndRefreshInCallActions();
if (status != null) {
LinphoneUtils._log("CallActivity", "if (status != null) {");
videoProgress.setVisibility(View.GONE);
status.refreshStatusItems(call, isVideoEnabled(call));
} else {
LinphoneUtils._log("CallActivity", "if (status ===== null) {");
}
} else if (state == State.CallUpdatedByRemote) {
LinphoneUtils._log("CallActivity", "} else if (state == State.CallUpdatedByRemote) {");
// If the correspondent proposes video while audio call
boolean videoEnabled = LinphonePreferences.instance().isVideoEnabled();
if (!videoEnabled) {
LinphoneUtils._log("CallActivity#Turn", "if (!videoEnabled) acceptCallUpdate(false);");
acceptCallUpdate(false);
}
boolean remoteVideo = call.getRemoteParams().getVideoEnabled();
boolean localVideo = call.getCurrentParamsCopy().getVideoEnabled();
boolean autoAcceptCameraPolicy = LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests();
if (remoteVideo && !localVideo && !autoAcceptCameraPolicy && !LinphoneManager.getLc().isInConference()) {
showAcceptCallUpdateDialog();
createTimerForDialog(SECONDS_BEFORE_DENYING_CALL_UPDATE);
}
// else if (remoteVideo && !LinphoneManager.getLc().isInConference() && autoAcceptCameraPolicy) {
// mHandler.post(new Runnable() {
// @Override
// public void run() {
// acceptCallUpdate(true);
// }
// });
// }
}
说明
在这个界面实际上就是管理接听话, 还有是否接受视频通话等.
何处调用
在LinphoneActivity开启的时候, 会对状态有个判断. 而LinphoneActivity是被LinphoneService调用的.
3.2 CallIncomingActivity.java
代码
mListener = new LinphoneCoreListenerBase() {
@Override
public void callState(LinphoneCore lc, LinphoneCall call, State state, String message) {
LinphoneUtils._log("CallIncomingActivity", "callState(LinphoneCore lc " + lc +
", LinphoneCall call " + call +
", State state " + state +
", String message) " + message +
"");
if (call == mCall && State.CallEnd == state) {
finish();
}
if (state == State.StreamsRunning) {
// The following should not be needed except some devices need it (e.g. Galaxy S).
LinphoneManager.getLc().enableSpeaker(LinphoneManager.getLc().isSpeakerEnabled());
}
}
};
说明
当有来电电话时, 调用此界面
何处调用
在CallActivity中, 有一个事件监听, 当收到IncomingReceived这个状态的时候调用.
3.3 CallOutgoingActivity.java
代码
mListener = new LinphoneCoreListenerBase() {
@Override
public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
if (call == mCall && State.Connected == state) {
if (!LinphoneActivity.isInstanciated()) {
return;
}
LinphoneActivity.instance().startIncallActivity(mCall);
finish();
return;
} else if (state == State.Error) {
// Convert LinphoneCore message for internalization
if (message != null && call.getErrorInfo().getReason() == Reason.Declined) {
displayCustomToast(getString(R.string.error_call_declined), Toast.LENGTH_SHORT);
} else if (message != null && call.getErrorInfo().getReason() == Reason.NotFound) {
displayCustomToast(getString(R.string.error_user_not_found), Toast.LENGTH_SHORT);
} else if (message != null && call.getErrorInfo().getReason() == Reason.Media) {
displayCustomToast(getString(R.string.error_incompatible_media), Toast.LENGTH_SHORT);
} else if (message != null && call.getErrorInfo().getReason() == Reason.Busy) {
displayCustomToast(getString(R.string.error_user_busy), Toast.LENGTH_SHORT);
} else if (message != null) {
displayCustomToast(getString(R.string.error_unknown) + " - " + message, Toast.LENGTH_SHORT);
}
}
if (LinphoneManager.getLc().getCallsNb() == 0) {
finish();
return;
}
}
};
说明
类似CallIncomingActivity的调用方式, 只是逻辑流程相反而已.
何处调用
跟CallIncomingActivity的调用方式相同, 只是状态不同, 走的逻辑不相同.
3.4 ChatFragment.java
代码
mListener = new LinphoneCoreListenerBase(){
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {
LinphoneAddress from = cr.getPeerAddress();
if (from.asStringUriOnly().equals(sipUri)) {
LinphoneService.instance().removeMessageNotification();
cr.markAsRead();
LinphoneActivity.instance().updateMissedChatCount();
adapter.addMessage(cr.getHistory(1)[0]);
String externalBodyUrl = message.getExternalBodyUrl();
LinphoneContent fileTransferContent = message.getFileTransferInformation();
if (externalBodyUrl != null || fileTransferContent != null) {
LinphoneActivity.instance().checkAndRequestExternalStoragePermission();
}
}
}
@Override
public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom room) {
if (chatRoom != null && room != null && chatRoom.getPeerAddress().asStringUriOnly().equals(room.getPeerAddress().asStringUriOnly())) {
remoteComposing.setVisibility(chatRoom.isRemoteComposing() ? View.VISIBLE : View.GONE);
}
}
};
说明
主要是处理接收消息的逻辑.
3.5 ChatListFragment.java
代码
mListener = new LinphoneCoreListenerBase() {
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {
refresh();
}
};
说明
更新消息列表
3.6 LinphoneActivity.java
代码
mListener = new LinphoneCoreListenerBase() {
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {
displayMissedChats(getUnreadMessageCount());
}
@Override
public void registrationState(LinphoneCore lc, LinphoneProxyConfig proxy, LinphoneCore.RegistrationState state, String smessage) {
if (state.equals(RegistrationState.RegistrationCleared)) {
if (lc != null) {
LinphoneAuthInfo authInfo = lc.findAuthInfo(proxy.getIdentity(), proxy.getRealm(), proxy.getDomain());
if (authInfo != null)
lc.removeAuthInfo(authInfo);
}
}
refreshAccounts();
if (getResources().getBoolean(R.bool.use_phone_number_validation)
&& proxy.getDomain().equals(getString(R.string.default_domain))) {
if (state.equals(RegistrationState.RegistrationOk)) {
LinphoneManager.getInstance().isAccountWithAlias();
}
}
if (state.equals(RegistrationState.RegistrationFailed) && newProxyConfig) {
newProxyConfig = false;
if (proxy.getError() == Reason.BadCredentials) {
//displayCustomToast(getString(R.string.error_bad_credentials), Toast.LENGTH_LONG);
}
if (proxy.getError() == Reason.Unauthorized) {
displayCustomToast(getString(R.string.error_unauthorized), Toast.LENGTH_LONG);
}
if (proxy.getError() == Reason.IOError) {
displayCustomToast(getString(R.string.error_io_error), Toast.LENGTH_LONG);
}
}
}
@Override
public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
LinphoneUtils._log("LinphoneActivity", "callState(" +
"LinphoneCore lc " + lc +
", LinphoneCall call " + call +
", LinphoneCall.State state " + state +
", String message " + message +
")");
if (state == State.IncomingReceived) {
LinphoneUtils._log("LinphoneActivity", "startActivity(new Intent(LinphoneActivity.instance(), CallIncomingActivity.class));");
startActivity(new Intent(LinphoneActivity.instance(), CallIncomingActivity.class));
} else if (state == State.OutgoingInit || state == State.OutgoingProgress) {
LinphoneUtils._log("LinphoneActivity", "startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class));");
startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class));
} else if (state == State.CallEnd || state == State.Error || state == State.CallReleased) {
LinphoneUtils._log("LinphoneActivity", "resetClassicMenuLayoutAndGoBackToCallIfStillRunning();");
resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
}
int missedCalls = LinphoneManager.getLc().getMissedCallsCount();
displayMissedCalls(missedCalls);
}
};
说明
功能主界面, 主要是用来处理所有状态的分配, 比如跳转到图像管理界面CallActivity, 显示主界面, 拨打电话界面.
3.7 LinphoneService.java
代码
LinphoneManager.getLc().addListener(mListener = new LinphoneCoreListenerBase() {
@Override
public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
LinphoneUtils._log("LinphoneService",
"callState(LinphoneCore lc " + lc +
", LinphoneCall call " + call +
", LinphoneCall.State state " + state +
", String message " + message +
")");
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) {
LinphoneService._log("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);
LinphoneService._log("!!!!!!!(missedCallCount > 1) , address = " + address + " , c = ");
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()) {
LinphoneService._log("globalState(LinphoneCore lc" +
", LinphoneCore.GlobalState state == " + state +
", String message == " + message);
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;
// }
LinphoneService._log("LinphoneCore lc" +
", LinphoneProxyConfig cfg == " + cfg +
", LinphoneCore.RegistrationState state == " + state +
", String smessage == " + smessage);
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);
}
}
}
});
说明
这个时非常重要的逻辑了, 是主要的监听服务. 而且弹出的Notification这里也有管理.
3.8 StatusFragment.java
代码
mListener = new LinphoneCoreListenerBase(){
@Override
public void registrationState(final LinphoneCore lc, final LinphoneProxyConfig proxy, final LinphoneCore.RegistrationState state, String smessage) {
if (!isAttached || !LinphoneService.isReady()) {
return;
}
if(lc.getProxyConfigList() == null){
statusLed.setImageResource(R.drawable.led_disconnected);
statusText.setText(getString(R.string.no_account));
} else {
statusLed.setVisibility(View.VISIBLE);
}
if (lc.getDefaultProxyConfig() != null && lc.getDefaultProxyConfig().equals(proxy)) {
statusLed.setImageResource(getStatusIconResource(state, true));
statusText.setText(getStatusIconText(state));
} else if(lc.getDefaultProxyConfig() == null) {
statusLed.setImageResource(getStatusIconResource(state, true));
statusText.setText(getStatusIconText(state));
}
try {
statusText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
lc.refreshRegisters();
}
});
} catch (IllegalStateException ise) {}
}
@Override
public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, String eventName, LinphoneContent content) {
if(!content.getType().equals("application")) return;
if(!content.getSubtype().equals("simple-message-summary")) return;
if (content.getData() == null) return;
int unreadCount = -1;
String data = content.getDataAsString();
String[] voiceMail = data.split("voice-message: ");
final String[] intToParse = voiceMail[1].split("/",0);
unreadCount = Integer.parseInt(intToParse[0]);
if (unreadCount > 0) {
voicemailCount.setText(unreadCount);
voicemail.setVisibility(View.VISIBLE);
voicemailCount.setVisibility(View.VISIBLE);
} else {
voicemail.setVisibility(View.GONE);
voicemailCount.setVisibility(View.GONE);
}
}
};
说明
显示音频视频的速率
**Audio**
Codec:opus / 48kHz
Encoder:An opus encoder.
Decoder:An opus decoder.
Upload bandwidth:31 kbits/s
Download bandwidth:32 kbits/s
ICE connectivity: Not activated
IP Familiy:ipV4
Sender loss rate: 0%
Receiver loss rate: 0%
Jitter buffer:32.79ms
**Video**
Encoder:A VP8 video encoder using libvpx library.
Decoder:A VP8 video decoder using libvpx library.
Upload bandwidth:194 kbits/s
Download bandwidth:0 kbits/s
ICE connectivity: not activated
IP Family:Ipv4
Sender losdd rate:0%
Recevier loss rate: 0%
Sent video resolution: 480x640
Received video resolution: 352*288
3.9 AssistantActivity.java
代码
mListener = new LinphoneCoreListenerBase() {
@Override
public void configuringStatus(LinphoneCore lc, final LinphoneCore.RemoteProvisioningState state, String message) {
if (progress != null) progress.dismiss();
if (state == LinphoneCore.RemoteProvisioningState.ConfiguringSuccessful) {
LOG("AssistantActivity goToLinphoneActivity();");
goToLinphoneActivity();
} else if (state == LinphoneCore.RemoteProvisioningState.ConfiguringFailed) {
Toast.makeText(AssistantActivity.instance(), getString(R.string.remote_provisioning_failure), Toast.LENGTH_LONG).show();
}
}
@Override
public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, RegistrationState state, String smessage) {
if (remoteProvisioningInProgress) {
if (progress != null) progress.dismiss();
if (state == RegistrationState.RegistrationOk) {
remoteProvisioningInProgress = false;
success();
}
} else if (accountCreated && !newAccount) {
if (address != null && address.asString().equals(cfg.getAddress().asString())) {
if (state == RegistrationState.RegistrationOk) {
if (progress != null) progress.dismiss();
if (LinphoneManager.getLc().getDefaultProxyConfig() != null) {
accountCreator.isAccountUsed();
}
} else if (state == RegistrationState.RegistrationFailed) {
if (progress != null) progress.dismiss();
if (dialog == null || !dialog.isShowing()) {
dialog = createErrorDialog(cfg, smessage);
dialog.show();
}
} else if (!(state == RegistrationState.RegistrationProgress)) {
if (progress != null) progress.dismiss();
}
}
}
}
};
说明
3.10 RemoteProvisioningActivity.java
代码
mListener = new LinphoneCoreListenerBase(){
@Override
public void configuringStatus(LinphoneCore lc, final RemoteProvisioningState state, String message) {
if (spinner != null) spinner.setVisibility(View.GONE);
if (state == RemoteProvisioningState.ConfiguringSuccessful) {
goToLinphoneActivity();
} else if (state == RemoteProvisioningState.ConfiguringFailed) {
Toast.makeText(RemoteProvisioningActivity.this, R.string.remote_provisioning_failure, Toast.LENGTH_LONG).show();
}
}
};
说明
3.11 RemoteProvisioningLoginActivity.java
代码
mListener = new LinphoneCoreListenerBase(){
@Override
public void configuringStatus(LinphoneCore lc, final LinphoneCore.RemoteProvisioningState state, String message) {
if (state == LinphoneCore.RemoteProvisioningState.ConfiguringSuccessful) {
//TODO
} else if (state == LinphoneCore.RemoteProvisioningState.ConfiguringFailed) {
Toast.makeText(RemoteProvisioningLoginActivity.this, R.string.remote_provisioning_failure, Toast.LENGTH_LONG).show();
}
}
};
说明
4. LinphoneCoreListener中callState()和transferState的区别
代码
/**
* Notifies progress of a call transfer.
* @param lc the LinphoneCore
* @param call the call through which the transfer was sent.
* @param new_call_state the state of the call resulting of the transfer, at the other party.
**/
void transferState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State new_call_state);
/** Call State notification
* @param state LinphoneCall.State
*/
void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message);
说明
transferState时一个新到的电话的状态, callstate是第一个通信的状态.
5. 监听状态是一个观察者模式
调用此方法注册Listener
linphonecore_jni.cc中
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addListener(JNIEnv* env, jobject thiz, jlong lc, jobject jlistener) {
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *) linphone_core_get_user_data((LinphoneCore *)lc);
LinphoneCoreVTable *vTable = linphone_core_v_table_new();
LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, jlistener, ljb);
linphone_core_v_table_set_user_data(vTable, ldata);
linphone_core_add_listener((LinphoneCore*)lc, vTable);
}
在vtabls.c中
void linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable){
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
_linphone_core_cbs_set_v_table(cbs, vtable, FALSE);
_linphone_core_add_callbacks(lc, cbs, FALSE);
linphone_core_cbs_unref(cbs);
}
因为要涉及到很多结构体的使用, 如果不分析结构体, 就没办法彻底的弄明白这个观察者模式时怎么来的. 这会又要涉及到很多的内容, 所以下一篇详细追踪.