可视对讲移动端SDK接口说明[Andriod]

更新时间:

1. 概述

1.1 编写目的

本文是可视对讲设备云对讲和呼手机功能SDK接口说明。

1.2 名词解释

名词

解释

IoT

物联网

2. 介绍

通过集成对接SDK可以使门禁设备快速实现包括门禁机呼叫APP、APP调看门禁机、门禁机呼叫⼿机号等对讲功能。本⽂旨在描述该SDK的集成⽅式及主要业务代码。

限制条件:

编译过程基于Android Studio 4.1.3

推荐使用GradlePlugin版本:4.1.2

推荐使用Gradle版本:6.5

推荐编译SDK版本:30

最小支持SDK版本:21

3. SDK集成方法

3.1 导入所需文件

新建或打开已有工程,拷贝leephone.aar包到app/libs目录下.

在app/build.gradle中添加aar包的引用,如图所示。

...
android {
  ...
    defaultConfig {
    ...
        ndk.abiFilters "armeabi-v7a", "arm64-v8a"
    }
}
...
repositories {
    flatDir {
        dirs 'libs' // aar dir
    }
}
...
dependencies {
 implementation(name:'leephone', ext:'aar')
  ...
}

3.2 在AndroidManifest.xml配置

⽀持的最低SDK版本为5.0:

<uses-sdk android:minSdkVersion="21" />

添加必要权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

3.3 代码混淆配置

如果有做代码混淆,请确保以下类不加入混淆

-keep class com.evideo.voip.** { *; }
-keep class com.lee.phone.** { *; }

4. 类及接口列表

4.1 类说明

类名

说明

EVVoipManager

负责登录SIP

EVVoipAccount

SIP会话

EVVoipCall

负责SIP通话

EVVideoView

负责视频显示

EVVoipCallParams

通话参数

4.2 接口说明

4.2.1流程关键接口

名称

类名

方法名

初始化

EVVoipManager

init(Context context, EVVoipManager.OnInitCallback callback)

反初始化

EVVoipManager

deInit(Context context)

登录SIP服务器

EVVoipManager

EVVoipAccount login(String sipnum, String password, String displayName, String domain, int port)

账号状态监听

EVVoipAccount

setAccountStateCallback(EVVoipAccount.AccountStateCallbackaccountStateCallback)

来电监听

EVVoipManager

setIncomingCallback(EVVoipManager.IncomingCallbackincomingCallback)

呼叫APP

EdgeBoxManager

callRoomID(String roomID, EVVoipCallParams params, EdgeBoxManager.OnCallRoomCallback callback)

接听

EVVoipCall

accept(EVVideoView display)

挂断

EVVoipCall

hangup()

通话状态监听

EVVoipCall

setCallStateCallback(EVVoipCall.CallStateCallbackcallStateCallback)

5. 主要业务流程

5.1 初始化

在进⾏对讲业务之前,需要先初始化该SDK,才能保证后续业务正常,后续的所有API调⽤都必须在SDK初始化成功的情况下执⾏。在应⽤的⽣命周期内,⼀般只进⾏⼀次初始化。

public static void init(Context context, EVVoipManager.OnInitCallback callback)

// 初始化对讲SDK
EVVoipManager.init(getApplicationContext(), new EVVoipManager.OnInitCallback() {
    @Override
    public void complete() {
        // 对讲SDK初始化成功
    }
    @Override
    public void error(int code) {
        // 对讲SDK初始化失败,错误代码code
    }
});

当不再使⽤对讲业务时,可以调⽤deInit进⾏SDK反初始化。

// 反初始化对讲SDK
EVVoipManager.deInit(getApplicationContext());

5.2 登入SIP服务器

在对讲SDK初始化成功之后,需要进⾏SIP服务器登入,登入成功后可以得到EVVoipAccount对象。

EVVoipAccount EVVoipManager.login(String sipnum, String password, String displayName, String domain, int port)

为了能够实时显示账号状态,本SDK提供 AccountStateCallback 接⼝实时监听当前账号状态。

mEVVoipAccount.setAccountStateCallback(new EVVoipAccount.AccountStateCallback() {
    @Override
    public void onState(EVVoipAccount.AccountState state) {
        /* 获取该账号的状态
         * AccountState.ONLINE 在线
         * AccountState.OFFLINE 离线
         * AccountState.LOGINPROCESS 登入中
         * AccountState.NONE ⽆账号、未登入
         */
    }
});

当不再使⽤对讲业务,可以通过以下接⼝进⾏登出操作。

mEVVoipAccount.logoutEdgeBox();

5.3 呼叫监听

为了使APP能够响应设备通话请求,需要注册⼀个来电回调监听接⼝。

EVVoipManager.setIncomingCallback(new EVVoipManager.IncomingCallback() {
    @Override
    public void inComing(EVVoipCall evCall) {
        // evCall表示当前来电的通话
    }
});

为了能够实时获取当前的通话状态,可以在EVVoipCall对象上设置⼀个通话状态回调接⼝。

evCall.setCallStateCallback(new EVVoipCall.CallStateCallback() {
    @Override
    public void onState(CallState state, EndReason reason) {
        // 参考⻔禁机呼叫APP示例
    }
});

5.4 通话接听

为了显示设备的对讲画面,需要提供⼀个EVVideoView作为视频容器,如果不提供则为⾳频通话。

private EVVideoView eVideoView;
public int accept(EVVideoView display) throws EVVoipException;
// 初始化视频绘制容器,EVVideoView是⼀个android.app.Fragment,⽬前只⽀持在xml布局⽂件中配置
mEVVideoView= (EVVideoView) getFragmentManager().findFragmentById(R.id.display_view);
try {
    // 响应监控请求
    evCall.accept(mEVVideoView);
} catch (EVVoipException e) {
    e.printStackTrace();
}

5.5 通话挂断

evVoipCall.setCallStateCallback(null);
try {
 evVoipCall.hangup();
} catch (EVVoipException e) {
 e.printStackTrace();
}

5.6 开门

通话中可以发送开门指令,在发送开门指令前先设置监听器,通过监听获取开门指令执行结果。

EVVoipCall.unlock

evVoipCall.setUnlockCallback(new EVVoipCall.UnlockCallback() {
 @Override
 public void onSuccess() {
        //开门成功
 }

 @Override
 public void onFailure() {
  //开门失败
 }
});
int ret = call.unlock();//开门

5.7 通话中呼叫监听

EVVoipManager.setSwitchCallback
mOnSwitchCallback = new OnSwitchCallBack() {

 @Override
 public void onSwitch(EVVoipCall call) {

 }

 @Override
 public void onResume(EVVoipCall call) {

 }

 @Override
 public void onPause(EVVoipCall call) {
    
 }
};
EVVoipManager.setSwitchCallback(mOnSwitchCallback);

5.8 对话视频

evVoipCall.setOnRemoteVideoMuteListener(new OnRemoteVideoMuteListener() {
 @Override
 public void onRemoteVideoMuteAnswer(boolean mute) {
 }

 @Override
 public void onRemoteVideoMuteOffer(boolean mute) {

 }
});

5.9 开关视频

evVoipCall.enableVideo

5.10 通话协议监听

evVoipCall.setOnIceNatListener(new OnIceNatListener() {
 @Override
 public void OnAudioIceNatListener(int iceNet) {
  case IceNatType.ICE_NAT_TYPE_HOST:
  case IceNatType.ICE_NAT_TYPE_SRFLX:
  case IceNatType.ICE_NAT_TYPE_PRFLX:
  case IceNatType.ICE_NAT_TYPE_RELAY:
    }

    @Override
    public void OnVideoIceNatListener(int iceNet) {
  case IceNatType.ICE_NAT_TYPE_HOST:
  case IceNatType.ICE_NAT_TYPE_SRFLX:
  case IceNatType.ICE_NAT_TYPE_PRFLX:
  case IceNatType.ICE_NAT_TYPE_RELAY:
 }
});
evVoipCall.setOnMonitorListener(new OnMonitorListener() {
 @Override
 public void onMonitor() {

 }
});

问题1:setOnMonitorListener接口作用

5.11 APP调看门禁机

呼叫对讲设备

evVoipCall = VoipManager.getInstance().call(sipNum, evVoipCallParams);

设置通话状态监听

evVoipCall.setCallStateCallback(new CallStateCallback {
 @Override
 void onState(EVVoipCall.CallState var1, EVVoipCall.EndReason var2) {
    
    }
});

设置呼叫失败监听

evVoipCall.setCallFailureCallback(new CallFailureCallback() {
 @Override
 public void onFailure() {
    }
});

开启麦克风(本地还是远端)

evVoipCall.enableMicrophone(true); //true-关闭麦克风,false-开启麦克风

开启扬声器

evVoipCall.enableSpeaker(true);    //true-开启扬声器,false-关闭扬声器

设置远程视频禁止监听

evVoipCall.setOnRemoteVideoMuteListener(new OnRemoteVideoMuteListener() {
 @Override
 public void onRemoteVideoMuteAnswer(boolean mute) {

 }

 @Override
 public void onRemoteVideoMuteOffer(boolean mute) {

    }
});

6.调试方法

6.1日志抓取方法

6.2关键流程日志

6.3 启动功能选择Activity

adb shell am start com.lee.phone.demo/com.lee.phone.demo.ChooseActivity

6.4 强制关闭Demo

adb shell am force-stop com.lee.phone.demo

7.FAQ

7.1 Debug版本工作正常,Release工作启动异常

2021-10-12 15:13:51.270 30733-30733/? A/DEBUG: Abort message: 'JNI DETECTED ERROR IN APPLICATION: mid == null
        in call to CallStaticIntMethod
        from void com.lee.phone.jni.LeeJni.leeInit(java.lang.String, java.lang.String, int, int, boolean, java.lang.String, java.lang.String, java.lang.String)'
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     x0  0000000000000000  x1  00000000000077db  x2  0000000000000006  x3  0000007ffe2299b0
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     x4  fefeff71731e1f97  x5  fefeff71731e1f97  x6  fefeff71731e1f97  x7  7f7f7f7f7f7f7fff
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     x8  00000000000000f0  x9  156478bff1817c09  x10 0000000000000001  x11 0000000000000000
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     x12 fffffff0fffffbdf  x13 ffffffffffffffff  x14 0000000000000004  x15 ffffffffffffffff
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     x16 00000072780c3958  x17 000000727809fa70  x18 00000072795bc000  x19 00000000000077db
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     x20 00000000000077db  x21 00000000ffffffff  x22 00000071e1f50300  x23 00000071f2565945
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     x24 00000071f258754b  x25 0000000000000001  x26 00000071f2bbc258  x27 0000007278bca9a0
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     x28 00000071f2a91338  x29 0000007ffe229a50
2021-10-12 15:13:51.270 30733-30733/? A/DEBUG:     sp  0000007ffe229990  lr  000000727804f704  pc  000000727804f730
2021-10-12 15:13:51.650 30733-30733/? A/DEBUG: backtrace:
2021-10-12 15:13:51.650 30733-30733/? A/DEBUG:       #00 pc 0000000000083730  /apex/com.android.runtime/lib64/bionic/libc.so (abort+160) (BuildId: 34c26ab262e93abd89e0bece8eedd768)
2021-10-12 15:13:51.650 30733-30733/? A/DEBUG:       #01 pc 00000000004b9f68  /apex/com.android.runtime/lib64/libart.so (art::Runtime::Abort(char const*)+2280) (BuildId: 0e606603700990d6d4117e187ef17d14)
2021-10-12 15:13:51.650 30733-30733/? A/DEBUG:       #02 pc 000000000000b458  /system/lib64/libbase.so (android::base::LogMessage::~LogMessage()+580) (BuildId: 34ca25523d4cef6dbfb222bd871ca0ed)
2021-10-12 15:13:51.650 30733-30733/? A/DEBUG:       #03 pc 000000000037885c  /apex/com.android.runtime/lib64/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+1584) (BuildId: 0e606603700990d6d4117e187ef17d14)
2021-10-12 15:13:51.650 30733-30733/? A/DEBUG:       #04 pc 00000000003b605c  /apex/com.android.runtime/lib64/libart.so (art::JNI::CallStaticIntMethod(_JNIEnv*, _jclass*, _jmethodID*, ...)+1464) (BuildId: 0e606603700990d6d4117e187ef17d14)
2021-10-12 15:13:51.650 30733-30733/? A/DEBUG:       #05 pc 0000000000290da0  /data/app/com.mqsz.life-JDTtNTsP89Vr90VYRjaCTQ==/lib/arm64/libleephone.so (lee_phone_detect_cameras+132) (BuildId: d1fde14fc5dc0807eb669a513e0e682a303e5ada)
2021-10-12 15:13:51.650 30733-30733/? A/DEBUG:       #06 pc 000000000045e644  /data/app/com.mqsz.life-JDTtNTsP89Vr90VYRjaCTQ==/lib/arm64/libleephone.so (lee_android_camera_init+120) (BuildId: d1fde14fc5dc0807eb669a513e0e682a303e5ada)

检查Release模式下混淆配置是否正确,参考《3.3 代码混淆配置》

7.2 leeMuteSpeaker和enableSpeaker区别

leeMuteSpeaker是SDK中把收到的音频直接扔掉,不通过扬声器播放这一步

enableSpeaker是android系统标准接口,切换扬声器和听筒