Android 访客端demo集成(含UI库)
代码下载
您可以通过以下两种方式获取到源代码:
- 下载代码压缩包:客服云sdk 及 Demo 下载 http://www.easemob.com/download/cs
项目集成:详细内容参考demo
app模块主体类介绍:
- LoginActivity:处理登录相关的逻辑,必须先登录环信服务器获取相关信息
- SettingFragment:通过扫码配置appkey相关信息
- CallActivity:视频通话页面(注意:V1.3.0版本采用此类进行唤起视屏通话页面)
- Calling:视频通话页面,兼容画中画模式(注意:V1.3.1版本之后采用此类进行唤起视屏通话页面)
- CallReceiver:用于接收视频邀请相关的信令
- DemoApplication:继承Application类,需要在AndroidManifest.xml内指定
- DemoHelper:初始化相关信息配置和注册
- HMSPushHelper:配置华为HMS推送相关的工具类
kefu-easeui模块主体类介绍:
- ChatFragment:聊天界面,app也可继承此fragment续写,参数传入示例可查看demo里的ChatActivity
- AgoraRtcEngine:音视频通话相关(基于声网sdk)
VECKit模块主体类介绍:
- VECKitCalling:视频通话页面唤起类
- CallVideoActivity:视频通话页面(没有赋予悬浮权限),普通效果
- VideoCallWindowService:视频通话页面(已赋予悬浮权限),画中画效果
- AgoraRtcEngine:音视频通话相关(基于声网sdk)
主要功能介绍
kefu-easeui模块:包含聊天、图片、表情、音视频相关内容的输入选择,可以实现自定义 音视频(基于声网音视频服务,使用环信 IM 作为信令通道的开源音视频模块)
注册视频信令广播(demo里CallReceiver广播类)
IntentFilter callFilter = new IntentFilter(ChatClient.getInstance().callManager().getIncomingCallBroadcastAction());
callFilter.addAction("calling.state");
CallReceiver callReceiver = new CallReceiver();
// register incoming call receiver
context.registerReceiver(callReceiver, callFilter);
相关音视频api介绍及使用如下:
创建视频引擎AgoraRtcEngine
/**
* 创建视频数据
* @param context Context
* @param appId String
* @param handler IAgoraRtcEngineEventHandler
*/
AgoraRtcEngine engine = AgoraRtcEngine.builder()
.addVideoWatermark() // 该方法将一张 PNG 图片作为水印添加到本地发布的直播视频流上
.setVideoEncodingDimension() // 视频编码像素。参数使用查看SDK里方法注解
.setVideoEncoderConfiguration() // 视频编码属性的定义。参数使用查看SDK里方法注解
.setRenderMode() // 设置视频渲染模式。参数使用查看SDK里方法注解
.setMirrorMode() // 设置视频镜像模式。参数使用查看SDK里方法注解
.setClientRole() // 设置直播场景下的用户角色。参数使用查看SDK里方法注解
.setChannelProfile() // 设置频道场景。参数使用查看SDK里方法注解
.build(getApplication(), "appid", new IAgoraRtcEngineEventHandler() {
@Override
public void onUserJoined(int uid, int elapsed) {
// 有人员加入时回调
}
@Override
public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
// 自己加入成功时回调
}
@Override
public void onLeaveChannel(RtcStats stats) {
// 离开channel时回调
}
@Override
public void onUserOffline(int uid, int reason) {
// 人员离开时回调
}
});
/**
* 创建 RendererView视图
*
* 请在主线程调用该方法
* @return SurfaceView
*/
engine.createRendererView();
engine.createRendererView(Context context);
/**
* 初始化远端用户视图
*
* 如果 App 不能事先知道对方的用户 ID,可以在 APP 收到 onUserJoined 事件时设置。
* 如果启用了视频录制功能,视频录制服务会做为一个哑客户端加入频道,因此其他客户端也会收到它的 onUserJoined 事件,
* App 不应给它绑定视图(因为它不会发送视频流),如果 App 不能识别哑客户端,可以在 onFirstRemoteVideoDecoded 事件时再绑定视图。
* 解除某个用户的绑定视图可以把 view 设置为空。退出频道后,SDK 会把远程用户的绑定关系清除掉。
* 注意:请在主线程调用该方法。如果你希望在通话中更新远端用户的渲染或镜像模式,请使用 setRemoteRenderMode 方法
* 如果你希望在通话中更新远端用户的渲染或镜像模式,请使用 setRemoteRenderMode 方法
* @param videoCanvas VideoCanvas
* @return 0: 方法调用成功。小于 0: 方法调用失败。
*/
engine.setupRemoteVideo(VideoCanvas videoCanvas);
engine.setupRemoteVideo(View surfaceView, int uid)
/**
* 更新远端视图显示模式
*
* @param uid uid
* @param renderMode 详细说明查看setRenderMode()方法注解
* @param mirrorMode 详细说明查看setMirrorMode()方法
* @return 0: 方法调用成功。小于 0: 方法调用失败。
*/
engine.setRemoteRenderMode(int uid, int renderMode, int mirrorMode);
/**
* 启用视频模块
*
* 该方法用于打开视频模式。可以在加入频道前或者通话中调用,在加入频道前调用,则自动开启视频模式,在通话中调用则由音频模式切换为视频模式。调用 disableVideo 方法可关闭视频模式。
* 成功调用该方法后,远端会触发 onUserEnableVideo(true) 回调
* 该方法设置的是内部引擎为开启状态,在频道内和频道外均可调用,且在 leaveChannel 后仍然有效。
* 该方法重置整个引擎,响应速度较慢,因此 Agora 建议使用如下方法来控制视频模块:
* enableLocalVideo:是否启动摄像头采集并创建本地视频流
* muteLocalVideoStream:是否发布本地视频流
* muteRemoteVideoStream:是否接收并播放远端视频流
* muteAllRemoteVideoStreams:是否接收并播放所有远端视频流
* @return 0: 方法调用成功。小于 0: 方法调用失败
*/
engine.enableVideo();
/**
* 关闭视频模块
*
* 该方法用于关闭视频。可以在加入频道前或者通话中调用,在加入频道前调用,则自动开启纯音频模式,在通话中调用则由视频模式切换为纯音频频模式。调用 enableVideo 方法可开启视频模式。
* 成功调用该方法后,远端会触发 onUserEnableVideo(false) 回调。
* 该方法设置的是内部引擎为禁用状态,在频道内和频道外均可调用,且在 leaveChannel 后仍然有效。
* 该方法重置整个引擎,响应速度较慢,因此 建议使用如下方法来控制视频模块:
* enableLocalVideo:是否启动摄像头采集并创建本地视频流
* muteLocalVideoStream:是否发布本地视频流
* muteRemoteVideoStream:是否接收并播放远端视频流
* muteAllRemoteVideoStreams:是否接收并播放所有远端视频流
* @return 0: 方法调用成功。小于 0: 方法调用失败
*/
engine.disableVideo();
/**
* 启用音频模块(默认为开启状态)
*
* 该方法设置的是音频模块为开启状态,在频道内和频道外均可调用,且在 leaveChannel 后仍然有效
* 该方法开启整个音频模块,响应速度较慢,因此建议使用如下方法来控制音频模块:
* enableLocalAudio:是否启动麦克风采集并创建本地音频流。
* muteLocalAudioStream:是否发布本地音频流。
* muteRemoteAudioStream:是否接收并播放远端音频流。
* muteAllRemoteAudioStreams:是否接收并播放所有远端音频流。
* @return 0: 方法调用成功。小于 0: 方法调用失败
*/
engine.enableAudio();
/**
* 关闭音频模块
*
* 该方法设置的是音频模块为禁用状态,在频道内和频道外均可调用,且在 leaveChannel 后仍然有效
* 该方法关闭整个音频模块,响应速度较慢,因此建议使用如下方法来控制音频模块
* enableLocalAudio:是否启动麦克风采集并创建本地音频流。
* muteLocalAudioStream:是否发布本地音频流。
* muteRemoteAudioStream:是否接收并播放远端音频流。
* muteAllRemoteAudioStreams:是否接收并播放所有远端音频流。
* @return 0: 方法调用成功。小于 0: 方法调用失败
*/
engine.disableAudio();
/**
* 开启/关闭本地音频采集。
*
* 当 app 加入频道时,它的语音功能默认是开启的。该方法可以关闭或重新开启本地语音,即停止或重新开始本地音频采集
* 该方法不影响接收远端音频流,enableLocalAudio(false) 适用于只听不发的用户场景。
* 语音功能关闭或重新开启后,会收到回调 onLocalAudioStateChanged ,并报告 LOCAL_AUDIO_STREAM_STATE_STOPPED(0) 或 LOCAL_AUDIO_STREAM_STATE_CAPTURING(1)
* 该方法与 muteLocalAudioStream 的区别在于:
* enableLocalAudio 开启或关闭本地语音采集及处理。使用 enableLocalAudio 关闭或开启本地采集后,本地听远端播放会有短暂中断。
* muteLocalAudioStream 停止或继续发送本地音频流。
* @param enabled 是否开启
* @return 0: 方法调用成功。小于 0: 方法调用失败。
*/
engine.enableLocalAudio(boolean enabled);
/**
* 取消或恢复订阅指定远端用户的音频流
*
* 该方法需要在加入频道后调用
* @param uid 指定用户的用户 ID
* @param muted 是否取消订阅指定远端用户的音频流,true:取消订阅。false:(默认)订阅
* @return 0: 方法调用成功。小于 0: 方法调用失败
*/
engine.muteRemoteAudioStream(int uid, boolean muted);
/**
* 取消或恢复订阅所有远端用户的音频流
*
* 成功调用该方法后,本地用户会取消或恢复订阅所有远端用户的音频流,包括在调用该方法后加入频道的用户的音频流
* @param muted 是否取消订阅所有远端用户的音频流。true: 取消订阅。false:(默认)订阅
* @return 0: 方法调用成功。小于 0: 方法调用失败
*/
engine.muteAllRemoteAudioStreams(boolean muted);
/**
* 取消或恢复发布本地音频流
*
* 该方法仅设置用户在 RtcChannel 频道中的音频发布状态。
* 成功调用该方法后,远端会触发 onRemoteAudioStateChanged 回调。
* 同一时间,本地的音视频流只能发布到一个频道。如果你创建了多个频道,请确保你只在一个频道中调用 muteLocalAudioStream(false),否则方法会调用失败并返回 -5 (ERR_REFUSED)。
* @param muted 是否取消发布本地音频流,true:取消发布,false:发布
* @return 0: 方法调用成功。小于 0: 方法调用失败。-5 (ERR_REFUSED):调用被拒绝
*/
engine.muteLocalAudioStream(boolean muted);
/**
* 开启/关闭扬声器播放
*
* 你可以调用 setEnableSpeakerphone 切换当前的音频路由。 成功切换音频路由后,SDK 会触发 onAudioRouteChanged 回调提示音频路由已更改。
* 该方法只设置用户在当前频道内使用的音频路由,不会影响 SDK 默认的音频路由。 如果用户离开当前频道并加入新的频道,则用户还是会使用 SDK 默认的音频路由
* 该方法需要在 joinChannel 后调用。
* 如果用户使用了蓝牙耳机、有线耳机等外接音频播放设备,则该方法的设置无效,音频只会通过外接设备播放。当有多个外接设备时,音频会通过最后一个接入的设备播放。
* @param enabled 设置是否开启扬声器播放,true:开启。音频路由为扬声器。false:关闭。音频路由为听筒。
* @return 0:方法调用成功。小于 0:方法调用失败
*/
engine.setEnableSpeakerphone(boolean enabled);
/**
* 取消或恢复发布本地视频流。
*
* 成功调用该方法后,远端会触发 onUserMuteVideo 回调。
* 同一时间,本地的音视频流只能发布到一个频道。如果你创建了多个频道,请确保你只在一个频道中调用 muteLocalVideoStream(false), 否则方法会调用失败并返回 -5 (ERR_REFUSED)。
* 该方法不会改变视频采集设备的使用状态。该方法的调用是否生效受 joinChannel 和 setClientRole 方法的影响
* @param muted 是否取消发布本地视频流。true:取消发布。false:发布。
* @return 0:方法调用成功。小于 0:方法调用失败。-5 (ERR_REFUSED):调用被拒绝
*/
engine.muteLocalVideoStream(boolean muted);
/**
* 切换前置/后置摄像头。
*
* 该方法需要在相机启动(如通过调用 startPreview 或 joinChannel 实现)后调用。
* @return 0: 方法调用成功。小于 0: 方法调用失败。
*/
engine.switchCamera();
/**
* 使用 uid 加入频道
*
* 该方法不支持相同的用户重复加入同一个频道,如果想要从不同的设备同时接入同一个频道,请确保每个设备上使用的 UID 是不同的
* 请确保用于生成 Token 的 App ID 和创建 IRtcEngine 对象时用的 App ID 一致
* @param token 在 app 服务端生成的用于鉴权的 Token
* @param channelName 要加入的渠道名
* @param optionalUid 用户 ID,32 位无符号整数。建议设置范围:1 到 (232-1),并保证唯一性。如果不指定(即设为 0),SDK 会自动分配一个, 并在 onJoinChannelSuccess 回调方法中返回,App 层必须记住该返回值并维护,SDK 不对该返回值进行维护
* @return 0:调用成功,小于 0:方法调用失败
* 调用失败将返回如下:
* ERR_INVALID_ARGUMENT(-2)
* ERR_NOT_READY(-3)
* ERR_REFUSED(-5)
* ERR_NOT_INITIALIZED(-7)
* ERR_JOIN_CHANNEL_REJECTED(-17):加入频道被拒绝。由于 SDK 不支持用户重复加入同一个 RtcChannel 频道, 当已经加入某个 RtcChannel 频道的用户再次调用该 RtcChannel 对象的加入频道方法时,会返回此错误码
*/
engine.joinChannel(String token, String channelName, int optionalUid);
/**
* 使用 uid 加入频道
*
* 该方法不支持相同的用户重复加入同一个频道,如果想要从不同的设备同时接入同一个频道,请确保每个设备上使用的 UID 是不同的
* 请确保用于生成 Token 的 App ID 和创建 IRtcEngine 对象时用的 App ID 一致
* @param token 在 app 服务端生成的用于鉴权的 Token
* @param channelName 要加入的渠道名
* @param optionalInfo 开发者需加入的任何附加信息。一般可设置为空字符串,或频道相关信息。该信息不会传递给频道内的其他用户。
* @param optionalUid 用户 ID,32 位无符号整数。建议设置范围:1 到 (232-1),并保证唯一性。如果不指定(即设为 0),SDK 会自动分配一个, 并在 onJoinChannelSuccess 回调方法中返回,App 层必须记住该返回值并维护,SDK 不对该返回值进行维护
* @param options 频道媒体设置选项:ChannelMediaOptions
* @return 0:调用成功,小于 0:方法调用失败
* 调用失败将返回如下:
* ERR_INVALID_ARGUMENT(-2)
* ERR_NOT_READY(-3)
* ERR_REFUSED(-5)
* ERR_NOT_INITIALIZED(-7)
* ERR_JOIN_CHANNEL_REJECTED(-17):加入频道被拒绝。由于 SDK 不支持用户重复加入同一个 RtcChannel 频道, 当已经加入某个 RtcChannel 频道的用户再次调用该 RtcChannel 对象的加入频道方法时,会返回此错误码
*/
engine.joinChannel(String token, String channelName, String optionalInfo, int optionalUid, ChannelMediaOptions options);
/**
* 离开当前频道
*
* 成功调用该方法离开频道后,会触发如下回调:
* 本地:onLeaveChannel.
* 远端:通信场景下的用户和直播场景下的主播离开频道后,触发 onUserOffline。
* @return 0:方法调用成功。小于 0:方法调用失败
*/
engine.leaveChannel();
接听通话
/**
* 接听通话
*/
engine.joinChannel(String token, String channelName, int uid)
发起视频通话
/**
* 发起视频通话
* @param chatInviteShoe msg内容
* @param toChatUsername IM服务号
*/
ChatClient.getInstance().callManager().callVideo(String chatInviteShoe, String toChatUsername);
拒绝接听
/**
* 拒接视频
* @param callId callId
* @param isConnected 是否已接通,false未接通
*/
ChatClient.getInstance().callManager().endCall(int callId, boolean isConnected);
拒绝接听
/**
* 挂断视频
* @param callId callId
* @param isConnected 是否已接通,true接通
*/
ChatClient.getInstance().callManager().endCall(int callId, boolean isConnected);
/**
* V1.3.1版本之后才可以使用此方法,需要悬浮权限,授予权限将会实现悬浮效果
* 主动唤起视频页面(访客端发起会话到座席端)
* @param context
*/
Calling.callingRequest(Context context);
/**
* V1.3.1版本之后才可以使用此方法,需要悬浮权限,授予权限将会实现悬浮效果
* 被动唤起视频页面(座席端发起会话到访客端)
* @param context
* @param intent
*/
Calling.callingResponse(Context context, Intent intent);
音视频(基于声网音视频服务,使用环信 IM 作为信令通道的开源音视频模块)相关详细方法及参数说明参考声网api地址:https://docs.agora.io/cn/Interactive%20Broadcast/API%20Reference/java/index.html
VECKit 模块音视频主要方法介绍
VECKit 模块(新版VEC)音视频(基于声网音视频服务,使用环信 IM 作为信令通道的开源音视频模块)
相关音视频api介绍及使用如下:
注册视频信令广播(demo里CallReceiver广播类)
IntentFilter callFilter = new IntentFilter(ChatClient.getInstance().callManager().getIncomingCallBroadcastAction());
callFilter.addAction("calling.state");
CallReceiver callReceiver = new CallReceiver();
// register incoming call receiver
context.registerReceiver(callReceiver, callFilter);
初始化相关操作
/**
* 注册通知
* @param classKey 当前类名。当调用unRegisterAgoraMessageNotify方法释放时传入相同类名
* @param message IAgoraMessageNotify接口,通知回调:
* zuoXiSendThreeUserRequest(ZuoXiSendRequestObj obj)当座席端邀请第三方用户加入时,回调此方法
* createFlatRoom(ZuoXiSendRequestObj obj) 创建电子白板房间时,回调此方法
*/
AgoraMessage.newAgoraMessage().registerAgoraMessageNotify(String classKey, IAgoraMessageNotify message);
/**
* 注销通知
* @param classKey 当前类名。registerAgoraMessageNotify方法传入相同类名
*/
AgoraMessage.newAgoraMessage().unRegisterAgoraMessageNotify(String classKey);
// 创建引擎
AgoraRtcEngine agoraRtcEngine = AgoraRtcEngine.builder().build(Context context, String appId, IRtcEngineEventHandler handler)
// 设置自己窗口视图
agoraRtcEngine.setupLocalVideo(surfaceView, AgoraRtcEngine.RENDER_MODE_HIDDEN, obj.getUid());
// 加入房间
agoraRtcEngine.joinChannel(obj.getToken(), obj.getChannel(), obj.getUid());
*注:详情参数设置参考demo
主动发送视频邀请信令(唤起视图页面)
// 主动向坐席发送信令(发送信令并且唤起视频视图)
VECKitCalling.callingRequest(Context context, String toChatUserName);
// 主动向坐席发送信令(只发送信令)
ChatClient.getInstance().callManager().callVecVideo(String content, String toChatUsername)
挂断视频信令
/**
* 主动发起视频邀请,坐席未接通状态。主动发送挂断信令
*/
VECKitCalling.endCallFromOff();
/**
* 视频已接通。发送挂断信令
* @param callBack 回调函数
*/
VECKitCalling.endCallFromOn(ValueCallBack<String> callBack);
/**
* 坐席发起视频邀请,访客未接通状态。访客发送挂断信令
* @param content 显示内容
*/
VECKitCalling.endCallFromZuoXi(String content);
被动接收到信令(唤起视图页面)
// 接收到坐席发来的信令(发送信令并且唤起视图)
VECKitCalling.callingResponse(Context context, Intent intent);
// 接收到坐席发来的信令(只发送信令)
/**
* 坐席发起视频邀请。访客发送接通信令
* @param content 显示内容
*/
VECKitCalling.acceptCallFromZuoXi(String content);
// 接收到坐席发来的信令,唤起满意度评价视图
VECKitCalling.callingRetry(Context context, String content);
智能辅助相关信令
// 注册接口,接收vec相关信令
AgoraMessage.newAgoraMessage().registerVecPushMessage(String classKey, IPushMessage callback);
// 释放接口
AgoraMessage.newAgoraMessage().unRegisterVecPushMessage(String classKey);
/**
* 智能辅助(手电筒):通知坐席端开启手电筒的状态
* @param isOk 是否开启成功:true开启成功,false开启失败
* @param msg 内容(通知坐席端开启失败的原因,如果isOK指定为true,msg传入"")
*/
AgoraMessage.sendFlashLight(boolean isOk, String msg);
/**
* 智能辅助(闪光灯):通知坐席端开启光灯的状态
* @param isOk 是否开启成功:true开启成功,false开启失败
* @param msg 内容(通知坐席端开启失败的原因,如果isOK指定为true,msg传入"")
*/
AgoraMessage.sendCameraTorch(boolean isOk, String msg);
/**
* 智能辅助(聚焦):通知坐席端开启的状态
* @param msg 内容(通知坐席端聚焦失败的原因,聚焦成功msg传入"")
*/
AgoraMessage.sendCameraFocus(String msg);
/**
* 智能辅助(麦克风):通知坐席端开启的状态
* @param msg 内容(通知坐席端开启失败的原因,麦克风开启成功msg传入"")
*/
AgoraMessage.sendMicrophone(String msg);
/**
* 智能辅助(相机):通知坐席端开启的状态
* @param msg 内容(通知坐席端开启失败的原因,相机开启成功msg传入"")
*/
AgoraMessage.sendCamera(String msg);
/**
* 智能辅助(切换相机):通知坐席端切换的状态
* @param msg 内容(通知坐席端切换相机失败的原因,切换相机成功msg传入"")
*/
AgoraMessage.sendChangeCamera(String msg);
详情使用请参考demo
音视频(基于声网音视频服务,使用环信 IM 作为信令通道的开源音视频模块)相关详细方法及参数说明参考声网api地址:https://docs.agora.io/cn/Interactive%20Broadcast/API%20Reference/java/index.html