Linphone callState 电话状态的监听状态(一)

2025-12-06 00:45:07

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 values = new Vector();

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

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 ConnectedStreamsRunning 接通中Paused 暂停Resuming ReferedErrorCallEndPausedByRemote 被远方暂停UpdatedByRemoteInconingEarlyMediaUpdatingReleasedEarlyUpdatedByRemoteEarlyUpdating

等我看完了, 怎么有这么多方法.

2.3 LinphoneCore.GlobalState Global状态

代码

/**

* linphone core states

*/

static public class GlobalState {

static private Vector values = new Vector();

/**

* 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");

说明

表示全局的状态

GlobalOffGlobalStartupGlobalOnGlobalStudownGlobalConfiguring

全局的一个状态

2.4 LinphoneCoreListenerBase.java

这个是实现所有LinphoneCoreListener方法, 目的是不用实现所有的方法, 而是有目的的实现其中的某个或某几个方法.

2.5 LinphoneChatMessage.State

代码

public static class State {

static private Vector values = new Vector();

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

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;

}

}

说明

主要是聊天中的一些状态

IdleInProgressDeliveredNotDeliveredFileTransferErrorFileTransferDoneDeliveredToUserDisplayed

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);

}

因为要涉及到很多结构体的使用, 如果不分析结构体, 就没办法彻底的弄明白这个观察者模式时怎么来的. 这会又要涉及到很多的内容, 所以下一篇详细追踪.

蔡依林阿云嘎等轮番登台,直播打歌综艺《打歌2025》开播
补时遭绝平!中国女足2-2韩国女足 姚伟传射+世界波 邵子钦建功