# 萤石云开放平台Android 音视频SDK使用说明
简介
本文档用于说明萤石开放平台音视频SDK Android版本接口使用。
名词解释
名词 | 释义 |
---|---|
accessToken | 访问令牌,由server返回给client用于认证 |
AppKey | 应用程序key,AppKey的申请可以参阅: https://open.ys7.com/view/app/app_edit.html |
deviceSerial | 设备序列号 |
CameraNo | 设备通道号 |
deviceSerial+CameraNo | 摄像头唯一标志 |
多方音视频 | 音视频通话的会议模式,可支持最多3方通话 |
功能介绍
功能 | 说明 |
---|---|
单设备呼叫 | 针对类手表设备,发起呼叫和通话功能,结合推送可做双向呼叫 |
多方通话 | 创建多方通话房间,并通过房间号,密码邀请多方进入房间通话 |
多方音频,视频,mic,摄像头控制 | 可根据业务需求操作对方音视频展示和本地音视频采集 |
工程配置
环境准备
支持 Android Studio 1.4 以上
支持 JDK 7.0 以上版本
支持 Android 手机系统 4.0 以上版本
创建应用
首先,你需要在萤石开放平台官网的 “ 开发者服务-我的应用-应用秘钥 ” 查看Appkey。
安装 SDK
SDK 的安装方式
使用 Gradle 获得
如果是之前采用过直接下载方式的需要删除之前拷贝进来的所有so库文件以及jar包
dependencies {
/*萤石SDK核心模块,必须依赖*/
implementation 'io.github.ezviz-open:ezviz-sdk:4.16.6'
/*视频通话模块,音视频通话必须依赖*/
implementation 'io.github.ezviz-open:videotalk:1.2.1'
}
配置工程(前提准备)
参考 萤石云开放平台Android SDK使用说明 完成SDK初始化等相关操作。
音视频SDK接入
步骤
- 创建通话控制器
- 设置通话回调
- 开启音视频通话
- 关闭音视频通话
- 释放音视频控制器
布局准备
<!-- 本机相机,可切换前置后置,开关录像等,sdk初始化必须 -->
<FrameLayout
android:id="@+id/vg_child_watch_video_talk_camera"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="@android:color/black">
<com.ezviz.sdk.videotalk.EvcLocalWindowView
android:id="@+id/view_child_watch_video_talk_camera"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"/>
</FrameLayout>
<!-- 对方画面,建议使用 TextureView-->
<FrameLayout
android:id="@+id/vg_child_watch_video_talk_player"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="@android:color/black">
<TextureView
android:id="@+id/view_child_watch_video_talk_player"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
手表(单设备呼叫)场景
1.创建通话控制器
// 带参数配置
EzvizVideoCall ezVideoCall = new EzvizVideoCall(EvcLocalWindowView, VideoCallParams, EvcMsgCallback)
// 不带参数配置
EzvizVideoCall ezVideoCall = new EzvizVideoCall(EvcLocalWindowView, EvcMsgCallback)
ezVideoCall.setLogPrintEnable(true) // debug模式下开启日志打印
注意在EvcMsgCallback的回调方法中设置画面视图,用于显示接通后对方的画面
void onCallEstablished(int width, int height, int clientId) {
runOnUiThread {
mEzvizVideoCall.setDisplay(new Surface(mPlayerView.getSurfaceTexture()), clientId)
}
}
// 建议对 TextureView 设置如下监听,否则容易出现黑屏或画面尺寸不同步(以下是 kotlin 语法)
private val mSurfaceTextureListener = object : TextureView.SurfaceTextureListener{
var mLastSurface: SurfaceTexture? = null
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {
LogUtil.d(TAG, "onSurfaceTextureAvailable")
mEzvizVideoCall?.setDisplay(Surface(surface!!))
if (mLastSurface == null){
mEzvizVideoCall?.setDisplay(Surface(surface))
mLastSurface = surface;
}else{
mEzvizVideoCall?.refreshWindow()
}
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {
// do nothing
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
mEzvizVideoCall?.setDisplay(null)
return true
}
override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
mEzvizVideoCall?.setDisplay(Surface(surface!!))
}
}
2.开启音视频通话(呼叫)
/**
* 呼叫设备
* @param deviceSerial
* @param selfId
*/
public void callVideoTalk(String deviceSerial, String selfId)
/**
* 接听呼叫
* @param deviceSerial
* @param selfId
* @param roomId
*/
public void answerVideoTalk(String deviceSerial, String selfId, int roomId)
/**
* 拒绝接听
* @param deviceSerial
* @param selfId
* @param roomId
*/
public void refuseVideoTalk(String deviceSerial, String selfId, int roomId)
// ======== 以上为预置功能,以下为完整方法,应对不通场景,一般不建议使用 =================
/*视频通话服务器域名*/
private const val SERVER_DOMAIN = "vtm.ys7.com"
/*视频通话服务器地址*/
private const val SERVER_PORT = 8554
/*对应手表联系人ID*/
private const val SELF_ID = "1234567891"
/* 完整方法,应对不同场景 */
private fun startVideoTalk(roomId: Int) {
if (!hasNeededPermissions()){
return
}
val param = EvcParam()
param.operation = operation // EvcOperationEnum.CALL 呼叫,EvcOperationEnum.ANSWER 接听
param.roomId = roomId // 接听时传,呼叫时不传
param.serverIp = SERVER_DOMAIN
param.serverPort = SERVER_PORT
param.selfClientType = EvcParamValueEnum.EvcClientType.ANDROID_PHONE // 固定
param.otherClientType = EvcParamValueEnum.EvcClientType.CHILD_WATCH // 固定
param.streamType = EvcParamValueEnum.EvcStreamType.VIDEO_TALK // 固定
param.otherId = mWatchSerial // 设备序列号
param.selfId = mSelfId //对应手表联系人ID 一般设备呼叫可不传
mEzvizVideoCall?.startVideoTalk(param)
}
3.结束通话和释放资源
// 停止通话
mEzvizVideoCall?.stopVideoTalk()
// 页面销毁前释放资源
public void onDestroy() {
super.onDestroy()
if (mEzvizVideoCall != null) {
mEzvizVideoCall?.release()
}
}
安全帽等(单设备)纯音频场景
// 创建通话控制器
EzvizVoiceCall mEzvizVoiceCall = new EzvizVoiceCall(EvcMsgCallback);
// 开启通话
mEzvizVoiceCall.startVideoTalk(Context context, String deviceSerial);
// 挂断,结束通话
mEzvizVoiceCall.stopVoiceTalk();
// 释放资源 onDestry() 中调用
mEzvizVoiceCall.release();
// ========== 以下为通话中功能方法 ==========
// 开启声音(对方声音)
mEzvizVoiceCall.openAudio();
// 静音(对方声音)
mEzvizVoiceCall.stopAudio();
多方会议通话
1. 基本流程
初始化
/**
* EvcLocalWindowView 本机视图
* nickname 当前设备在会议中显示的名称
* enableCamera 进入会议时是否开启相机
* enableMic 进入会议时是否开启麦克风
* EZMeetingCall.CallBack 会议通话回调
* VideoCallParams 相机,画面, fps,I帧等参数 -- 可不传
*/
EZMeetingCall mEZMeetingCall = new EZMeetingCall(EvcLocalWindowView view, String nickname, boolean enableCamera, boolean enableMic, EZMeetingCall.CallBack mMettingCallback, VideoCallParams)
// debug 下开启日志
mEZMeetingCall.setLogPrintEnable(true)
当前用户:创建会议,可带设备创建
// 1. 创建会议同时,呼叫一台设备
mEZMeetingCall.createMeetingWithDevice(mDeviceSerial?:"", mChannelId, mPassword)
// 2. 单纯创建会议房间
mEZMeetingCall.createMeeting(mPassword)
其他用户:主动加入房间
mEZMeetingCall.joinMeeting(mInputtedRoomID, mPassword)
退出会议房间
if (mEZMeetingCall != null) {
mEZMeetingCall?.quitMeeting()
mEZMeetingCall = null
}
补充,通话中的功能
// 当有用户加入会议(房间)时,调用该方法显示用户画面, cameraView 为 TextureView
mEZMeetingCall.showJoinUser(cameraView, clientId)
// 当有用户从房间退出时调用,自动销毁画面
mEZMeetingCall.leaveRoom(this.clientId)
2. 创建/加入房间回调
EZMeetingCall.CallBack {
// 异常回调
override fun onError(code: Int, message: String) {
showToast("onError: $code\n$message")
if (code == 50017) {
// 已被人接听或房间已满
} else if (code == 50103 || code == 50106) {
// 已被人接听或房间已满
} else if (code == 10152) {
// 没有麦克风权限
} else if (code == 20153) {
// 没有相机权限
} else if (code == 50105) {
// 设备正在通话中
} else if (code == 50007 || code == 50005) {
// 网络断开,退出房间
finish()
} else if(code == EvcErrorMessage.MULTI_CALL_FAILED_DEVICE_ENCRYPT.code){ // 300002
showToast("不支持加密设备,退出房间")
finish()
}
}
// 房间创建回调
override fun onRoomCreated(roomId: Int) {
showToast("onRoomCreated: $roomId")
// 返回房间号,建议自行保存,用于其他端加入会议房间使用
}
// 有用户进入房间
override fun onJoinRoom(roomId: Int, clientId: Int, username: String) {
runOnUiThread {
// 展示进入房间的用户 cameraView 为 TextureView
mEZMeetingCall.showJoinUser(cameraView, clientId)
}
}
//音量状态回调
override fun onClientStat(clientId: Int, volume: Int){
runOnUiThread{
changeUserVolume(clientId, volume)
}
}
//回调静音状态
override fun onClientUpdated(bavJoinInfo: JNAApi.BavJoinInfo?){
}
// 用户 clientId 的第一帧画面到来时回调
override fun onFirstFrameDisplayed(width: Int, height: Int, clientId: Int) {
}
// 当用户 clientId 退出房间时回调
override fun onQuitRoom(roomId: Int, clientId: Int) {
runOnUiThread {
// 解绑用户的视图
mEZMeetingCall.leaveRoom(clientId)
}
}
// 网络较差时回调
override fun onBadNet(delayTimeMs: Int) {
runOnUiThread {
showToast(getString(R.string.video_talk_signal_weak))
}
}
}
3. 补充功能,通话中
// 对会议中某个用户进行静音,只在当前设备生效
mEZMeetingCall.mute(isNute, clientId)
// 是否在通话中
mEZMeetingCall.isTalking()
// 是否开启相机
mEZMeetingCall.enableCamera(boolean isEnable)
// 是否开启麦克风
mEZMeetingCall.enableMic(boolean isEnable)
// 前置后置切换
mEZMeetingCall.switchCamera()
4. 注意
// 建议加上以下代码,保证在回到桌面后,再次回到app中 相机功能正常
override fun onPause() {
super.onPause()
mEZMeetingCall?.enableCamera(false)
}
override fun onRestart() {
super.onRestart()
mEZMeetingCall?.enableCamera(true)
}
5. 云录制
//创建录制项目:
fun onClickCreateProject(view: View){
mEZMeetingCall?.createProject(accessToken, projectId, projectName) //projectId 项目Id, projectName 项目名
}
//点击开始录制会议
fun onClickStartRecord(view: View){
//mRoomId: 房间号,mClient: 加入房间的id(使用","分割),projectId: 项目Id, fileId: 录制的文件Id,mCustomId: 开启录制会议传入的唯一字段
mEZMeetingCall?.startConRecord(accessToken, mRoomId, mClient, projectId, fileId, mCustomId)
}
//点击停止录制会议
onClickStopRecord(view: View){
//mRoomId:会议房间号,mCustomId:开启录制会议传入的唯一字段
mEZMeetingCall?.stopConRecord(AccessToken, mRoomId, mCustomId)
}
//点击查找录制文件
onClickSearchRecord(view: View){
//projectId:录制会议的项目Id, fileId:录制的文件Id
mEZMeetingCall?.searchConRecord(accessToken, projectId, fileId)
·}
}
若文档有未尽之处,请参考以下资料。 1.萤石SDK demo,点击跳转到github下载